主要是hibernate-validator依赖,可以直接引入,也可以引入spring-boot-starter-validation
org.springframework.boot spring-boot-starter-validation

- MethodArgumentNotValidException:入参为实体类,参数校验失败抛出的异常
- ConstraintViolationException:入参不是实体类,参数校验失败抛出的异常
- NotReadablePropertyException:入参为实体类集合,参数校验失败抛出的异常
@RestControllerAdvice
public class CommonExceptionHandler {/*** 入参为实体类,参数校验失败抛出的异常MethodArgumentNotValidException拦截** @param ex* @return*/@ExceptionHandler({MethodArgumentNotValidException.class})@ResponseStatus(HttpStatus.OK)@ResponseBodypublic BaseResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {BindingResult bindingResult = ex.getBindingResult();StringBuilder sb = new StringBuilder("校验失败:");for (FieldError fieldError : bindingResult.getFieldErrors()) {sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");}String msg = sb.toString();return BaseResponse.FAILURE(msg);}/*** 入参不是实体类,参数校验失败抛出的异常ConstraintViolationException拦截** @param ex* @return*/@ExceptionHandler({ConstraintViolationException.class})@ResponseStatus(HttpStatus.OK)@ResponseBodypublic BaseResponse handleConstraintViolationException(ConstraintViolationException ex) {return BaseResponse.FAILURE(ex.getMessage());}/*** 入参为实体类集合,参数校验失败抛出的异常NotReadablePropertyException拦截,但无法获取哪个字段参数校验失败** @param ex* @return*/@ExceptionHandler({NotReadablePropertyException.class})@ResponseStatus(HttpStatus.OK)@ResponseBodypublic BaseResponse handleNotReadablePropertyException(NotReadablePropertyException ex) {return BaseResponse.FAILURE(ex.getMessage());}
}
根据不同场景,使用上文1小节提到的常用注解进行校验,比如@NotNull
- 【举个栗子】:入参account不能为null,长度必须在【6,20】之间

【实体类】:
@Data
public class UserDTO {@NotNullprivate Long userId;@Length(min = 2, max = 10)private String userName;@Validprivate Job job;@Valid@NotEmptyprivate List banks;@Datapublic static class Job {@NotNullprivate Long jobId;@Length(min = 2, max = 10)private String jobName;}@Datapublic static class Bank {@Length(min = 2, max = 10)private String bankName;@NotNull@Length(min = 2, max = 10)private String position;}
}
【接口方法】:
@PostMapping("/save")public BaseResponse saveUser(@RequestBody @Validated UserDTO userDTO) {// 校验通过,才会执行业务逻辑处理return BaseResponse.SUCCESS();}
实体类的字段加上注解,接口方法中加上 @Validated 注解即可

- 往往实体类里面还包含则其它实体类,这时再嵌套的实体类加上@Valid即可
- 嵌套的实体类正常使用注解校验,当然接口方法要加上 @Validated 注解
- 不同场景,允许嵌套实体类为空,只要不标注@NotNull即可;实体类内添加校验注解,只要嵌套实体类不为空,就会校验


- 往往实体类里面还包含则其它实体类集合,这时再嵌套的实体类加上@Valid即可
- 嵌套的实体类正常使用注解校验,当然接口方法要加上 @Validated 注解


- 参数列表下使用List去接,即便实体类添加了参数校验注解,但是不会生效
- 需要自定义一个list集合来接收参数,并使用@Delegate注解(可以不用手动重写父类方法)
- 校验失败会抛出NotReadablePropertyException异常,如果全局异常拦截,,却无法获取哪个字段参数校验失败;栗子没有拦截
public class ValidationList implements List {@Delegate // @Delegate是lombok注解 ,1.18.6以上版本可支持@Valid // 一定要加@Valid注解public List list = new ArrayList<>();// 一定要记得重写toString方法@Overridepublic String toString() {return list.toString();}
}



- 不同场景共用同一个实体类,而且校验规则不一样,这时可以使用分组校验
- 使用时,在对于的注解加上group即可,值为定义的类或接口都可以,如 @NotNull(groups = {Update.class})
- 接口参数列表使用的@Validated(UserDTO1.Save.class) ,也要标注用的哪个分组规则
【实体类】:
@Data
public class UserDTO1 {@NotNull(groups = {Update.class})private Long userId;@Length(min = 2, max = 10, groups = {Save.class})private String userName;@Validprivate Job job;@Datapublic static class Job {@NotNull(groups = {Update.class})private Long jobId;@Length(min = 2, max = 10, groups = {Save.class})private String jobName;}/*** 保存的时候校验分组*/public interface Save {}/*** 更新的时候校验分组*/public interface Update {}
}
【举个栗子】:添加时userId允许为空,更新时不允许为空


原理和更多内容可以查看参考链接二
【参考链接】:
·
参考一:Hibernate Validator 参数验证 单个实体类与List集合的验证
参考二:SpringBoot 实现接口的各种参数校验