当前位置: 首页 > news >正文

使用JDK的数据校验和Spring的自定义注解校验前端传递参数的两种方法

第一种:JDK的数据校验注解

    @PostMapping("/test")public String test(QueryParam param, @RequestHeader(value = "App_key") String App_key,@RequestHeader(value = "App_secret") String App_secret) throws IOException {param.setApp_key(App_key);param.setApp_secret(App_secret);return service.test(param);}
@Data
public class QueryParam {private String url;private String App_key;private String App_secret;
}

QueryParam 里面的 url 为必传参数,当前端没有传递的时候,我需要报错提示前端,需要怎么做呢?

  1. 在QueryParam 里面的 url 字段上加上JDK的 NotBlank 注解
@Data
public class QueryParam {@NotBlank(message = "url参数不能为空")private String url;private String App_key;private String App_secret;
}
  1. 在接口的 QueryParam 参数前面加上 @Valid 注解
    @PostMapping("/test")public String test(@Valid QueryParam param, @RequestHeader(value = "App_key") String App_key,@RequestHeader(value = "App_secret") String App_secret) throws IOException {param.setApp_key(App_key);param.setApp_secret(App_secret);return service.test(param);}
  1. 在全局异常控制器中获取到 @NotBlank 注解上的描述信息,并返回给前端。
package com.tyler.web.exception;/*** 全局异常处理器*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 方法参数校验失败*/@ExceptionHandler(MethodArgumentNotValidException.class)public Result<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {e.printStackTrace();String errorMessage = e.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage) // 获取注解中定义的 message.findFirst().orElse("参数校验错误");return Result.fail(400, errorMessage, e.getMessage());}
}

这样写完之后就可以开启校验了。返回给前端的效果如下:

{"code": 400,"flag": false,"desc": "url参数不能为空","cause": "Validation failed for argument [0] in public java.lang.String com.yxai.web.controller.transfer.TransferController.entityExtraction(com.yxai.common.params.QueryParam,byte[],java.lang.String,java.lang.String) throws java.io.IOException: [Field error in object 'queryParam' on field 'url': rejected value [null]; codes [NotBlank.queryParam.url,NotBlank.url,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [queryParam.url,url]; arguments []; default message [url]]; default message [url参数不能为空]] ","traceId": "3806dae5-d8bc-48b0-8164-b947483c83e1","data": null
}

第二种:使用Spring的自定义注解校验

现在我想对接口上的 App_key 和 App_secret 做校验,这两个 header 也是必传字段,我需要怎么做呢?

在 Spring Boot 里可以借助@Validated注解和自定义校验注解达成对请求头参数的校验。当用户未传递App_key和App_secret时,就会给出相应的报错提示。

下面是具体的实现步骤与代码示例:

1. 自定义校验注解

先创建自定义的校验注解,用来校验请求头参数是否为空。

import com.tyler.web.utils.validator.NotEmptyValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;// 自定义注解,用于校验字符串是否为空
@Target({METHOD,FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = NotEmptyValidator.class)
public @interface NotEmpty {String message() default "该参数为必传参数";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}

2. 实现校验逻辑

接着实现校验注解对应的校验器。

import com.tyler.web.annotation.NotEmpty;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;// 自定义注解的校验器
public class NotEmptyValidator implements ConstraintValidator<NotEmpty, String> {@Overridepublic void initialize(NotEmpty constraintAnnotation) {}@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {return value != null && !value.isEmpty();}
}
  1. 在接口方法上使用校验注解

最后在接口方法的请求头参数上运用自定义的校验注解。

    @PostMapping("/test")public String test(@Valid QueryParam param, @RequestHeader(value = "App_key") @NotEmpty(message = "App_key为必传参数") String App_key,@RequestHeader(value = "App_secret") @NotEmpty(message = "App_secret为必传参数") String App_secret) throws IOException {param.setApp_key(App_key);param.setApp_secret(App_secret);return service.test(param);}

然后在前端试一下不传递 App_key 或 App_secret, 你会发现返回结果如下:

{"code": 200000,"flag": false,"desc": "系统异常","cause": "Required request header 'App_secret' for method parameter type String is not present","traceId": "0fb0ccb5-c2cb-4dfd-b4bf-030a0c18bc89","data": null
}

似乎我们写的代码没有生效。

这个问题在于 Spring 框架在执行自定义校验逻辑之前,就因为请求头缺失而抛出了异常。@RequestHeader注解默认要求参数必须存在,若缺失就会直接抛出异常,不会触发后续的自定义校验。

我们可以把@RequestHeader的required属性设为false,允许请求头缺失,之后再通过自定义校验注解进行检查。以下是修改后的代码:

    @PostMapping("/test")public String test(@Valid QueryParam param, @RequestHeader(value = "App_key", required = false) @NotEmpty(message = "App_key为必传参数") String App_key,@RequestHeader(value = "App_secret", required = false) @NotEmpty(message = "App_secret为必传参数") String App_secret) throws IOException {param.setApp_key(App_key);param.setApp_secret(App_secret);return service.test(param);}

修改点说明:

把@RequestHeader的required属性设置成false,这样即便请求头缺失,Spring 也不会立即抛出异常,而是会继续执行后续的自定义校验逻辑。当App_key或App_secret为空时,@NotEmpty注解会发挥作用,抛出相应的校验异常。

然后前端试一下不传递 App_secret, 会返回如下结果:

{"code": 200001,"flag": false,"desc": "未知异常","cause": "receiptCropAndRecogMulti.App_secret: App_secret为必传参数","traceId": "d6d83dfd-fd05-456e-a3de-ed5f180e3b07","data": null
}

但是我觉得这个返回结果不好看,我想要 desc 返回我定义的描述信息,怎么做呢?

当 App_secret 或 App_key 缺失的时候,代码会抛出 ConstraintViolationException 异常,所以我们需要在全局异常控制器里面捕捉该异常,然后对其进行处理即可。

package com.tyler.web.exception;/*** 全局异常处理器*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 方法参数校验失败*/@ExceptionHandler(MethodArgumentNotValidException.class)public Result<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {e.printStackTrace();String errorMessage = e.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage) // 获取注解中定义的 message.findFirst().orElse("参数校验错误");return Result.fail(400, errorMessage, e.getMessage());}/*** 自定义注解参数错误*/@ExceptionHandler(ConstraintViolationException.class)public Result<Object> handleBindException(ConstraintViolationException e) {e.printStackTrace();ConstraintViolation<?> violation = e.getConstraintViolations().iterator().next();return Result.fail(400, violation.getMessage(), e.getMessage());}
}

然后再请求一次,返回结果如下:

{"code": 400,"flag": false,"desc": "App_key为必传参数","cause": "entityExtraction.App_key: App_key为必传参数","traceId": "a4537203-3820-4442-9c35-e3a9f653c489","data": null
}

这就是我想要的效果了,到此本教程结束。

相关文章:

  • 2025吃鸡变声器软件推荐
  • COMEM光纤温度传感器Optocon:可靠稳定的温度监测方案
  • (002)Excel 使用图表,统计
  • 阅读MySQL实战45讲第11天
  • PCL实时动态加载显示点云功能以及laslib配置
  • Python项目-支持自然语言处理
  • 湖北理元理律师事务所:债务优化的法律机制与民生实践
  • 【阿里云大模型高级工程师ACP习题集】2.6.用插件扩展答疑机器人的能力边界
  • AI与IT协同的典型案例
  • C++——哈希表
  • 【C++】类和对象(4)
  • 线段树底层逻辑探讨-P3373-P1438
  • python 线程池顺序执行
  • 夜莺监控V8(Nightingale)二进制部署教程(保姆级)
  • BZOJ.疯狂的馒头
  • 单片机-89C51部分:7、中断
  • 无刷空心杯电机及机器人灵巧手的技术解析与发展趋势
  • ECMAScript 版本
  • 意法半导体(ST)重磅收购Deeplite,边缘AI版图再扩张
  • LangChain4j +DeepSeek大模型应用开发——3 人工智能服务 AIService
  • 众信旅游:去年盈利1.06亿元,同比增长228.18%
  • 俄罗斯延长非法滞留外国人限期离境时间至9月
  • 葡萄牙、西班牙发生大范围停电
  • 央行副行长:研究建立民营中小企业增信制度,破解民营中小企业信用不足等融资制约
  • 戴昕谈隐私、数据、声誉与法律现实主义
  • 俄军方:已完成库尔斯克地区全面控制行动