springboot 参数校验 @Validated 以及 @Valid
1、requestParam参数校验
描述:通常用于get请求或者请求参数比较少的情形。
校验生效的前提:必须在Controller类上标注@Validated注解,在方法或者参数前添加无效!
如果校验失败,会抛出ConstraintViolationException异常。
@GetMapping("/findByNo")
public Result findByNo(@RequestParam @NotBlank(message = "参数不能为空!") String orderNo) throws Exception {
String str = "请求成功!";
return new Result(ResultCode.SUCCESS, str);
}
2、pathVariable参数校验
描述:通过{}来动态配置请求路径,并将请求路径当成方法的入参之一。
校验生效的前提:必须在Controller类上标注@Validated注解,在方法或者参数前添加无效!
如果校验失败,会抛出ConstraintViolationException异常。
@GetMapping("/findByNo/{orderNo}")
public Result findByNo(@PathVariable @Max(message = "最大值不能超过20!", value = 20) Integer orderNo) throws Exception {
String str = "请求成功!";
return new Result(ResultCode.SUCCESS, str);
}
3、requestBody参数校验(application/json)
当请求方法入参有@RequestBody注解的时候,spring会将它识别成JSON格式的请求,要求调用方必须发送application/json格式的数据;
需要在实体类的字段上添加 约束注解 例如:@NotBlank ; 在接口参数上使用@Valid和@Validated都可以;
如果校验失败,会抛出MethodArgumentNotValidException异常。
@PostMapping("/save")
public Result saveHmi(@Validated @RequestBody Dev dev) {
devService.save(dev);
return new Result(ResultCode.SUCCESS);
}
4、表单请求参数校验(application/x-www-form-urlencoded)
当请求方法入参只有实体类接收的时候,spring会将它识别成FORM表单请求,要求调用方必须发送application/x-www-form-urlencoded格式的数据;
需要在实体类的字段上添加 约束注解 例如:@NotBlank ; 在接口参数上使用@Valid和@Validated都可以;
如果校验失败,会抛出BindException异常。
@PostMapping("/save")
public Result saveHmi(@Validated Dev dev) {
devService.save(dev);
return new Result(ResultCode.SUCCESS);
}
5、配置:
Spring Validation默认会校验完所有字段,然后才抛出异常。可以通过一些简单的配置,开启Fali Fast模式,一旦校验失败就立即返回。
@Configuration
public class WebParamValidateConfig {
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//failFast的意思只要出现校验失败的情况,就立即结束校验,不再进行后续的校验。
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}
6、统一异常处理
@ControllerAdvice是一个增强的 Controller。使用这个 Controller,可以实现三个方面的功能:
全局异常处理
全局数据绑定
全局数据预处理
只拦截Controller,不会拦截Interceptor的异常
@RestControllerAdvice(basePackages = "xxx.xxx.xxx.controller")
public class GlobalExceptionHandler {
//处理@RequestBody 参数校验
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result methodArgumentNotValidException(MethodArgumentNotValidException e) {
return new Result(false, ResultCode.FAIL.code(), e.getBindingResult().getFieldError().getDefaultMessage(), null);
}
//处理@RequestParam 和 @PathVariable 参数校验
@ExceptionHandler(value = ConstraintViolationException.class)
public Result methodArgumentNotValidException(ConstraintViolationException e) {
String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));
return new Result(false, ResultCode.FAIL.code(), message, null);
}
//处理 application/x-www-form-urlencoded 参数校验
@ExceptionHandler(value = BindException.class)
public Result methodArgumentNotValidException(BindException e) {
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
return new Result(false, ResultCode.FAIL.code(), message, null);
}
}
7、feign接口校验
在 FeignClient方法中使用@Validated校验传参; 在类上添加 @Validated 在方法参数上添加 @Valid ,必须组合使用
如果校验失败,会抛出ConstraintViolationException异常。
@FeignClient("xxx")
@Validated
public interface UserInviteActFeignClient {
@PostMapping(value = "/saveDev")
Result saveDev(@RequestBody @Valid Dev dev);
}
8、嵌套校验
当入参实体类的某字段也是对象时,这时,需要对该对象里的字段进行校验时,这就牵扯到了:嵌套校验;
此时,入参实体类的对应的字段对象,必须标记@Valid注解。
public class Dev {
//该字段是一个对象
@Valid
private DevAttr attr;
}
9、集合校验
如果请求体直接传递了json数组给后台,并希望对数组中的每一项都进行参数校验。
public class ValidationList<E> implements List<E> {
@Delegate
@Valid
public List<E> list = new ArrayList<>();
@Override
public String toString() {
return list.toString();
}
}
@PostMapping("/saveList")
public Result saveList(@RequestBody @Validated ValidationList<Dev> devList) {
return new Result(ResultCode.SUCCESS);
}