Hibernate-Validator 接口参数校验 | 嵌套参数校验

Posted 做猪呢,最重要的是开森啦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate-Validator 接口参数校验 | 嵌套参数校验相关的知识,希望对你有一定的参考价值。

0. 依赖:

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

<!--里面间接引入hibernate-validator -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

1. 常用注解:

2. 全局异常处理:

  • MethodArgumentNotValidException:入参为实体类,参数校验失败抛出的异常
  • ConstraintViolationException:入参不是实体类,参数校验失败抛出的异常
  • NotReadablePropertyException:入参为实体类集合,参数校验失败抛出的异常

@RestControllerAdvice
public class CommonExceptionHandler 

    /**
     * 入参为实体类,参数校验失败抛出的异常MethodArgumentNotValidException拦截
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public 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)
    @ResponseBody
    public BaseResponse handleConstraintViolationException(ConstraintViolationException ex) 
        return BaseResponse.FAILURE(ex.getMessage());
    

    /**
     * 入参为实体类集合,参数校验失败抛出的异常NotReadablePropertyException拦截,但无法获取哪个字段参数校验失败
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(NotReadablePropertyException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public BaseResponse handleNotReadablePropertyException(NotReadablePropertyException ex) 
        return BaseResponse.FAILURE(ex.getMessage());
    

3. 使用场景:

3.1. 接口参数列表校验:

根据不同场景,使用上文1小节提到的常用注解进行校验,比如@NotNull

  • 【举个栗子】:入参account不能为null,长度必须在【6,20】之间

3.2. 实体类参数校验:

【实体类】:


@Data
public class UserDTO 

    @NotNull
    private Long userId;

    @Length(min = 2, max = 10)
    private String userName;

    @Valid
    private Job job;

    @Valid
    @NotEmpty
    private List<Bank> banks;

    @Data
    public static class Job 

        @NotNull
        private Long jobId;

        @Length(min = 2, max = 10)
        private String jobName;

    

    @Data
    public 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();
    
3.2.1. 不包含嵌套属性的实体类参数校验:

实体类的字段加上注解,接口方法中加上 @Validated 注解即可

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

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


3.2.4. 接口参数列表为实体类集合参数校验:
  • 参数列表下使用List去接,即便实体类添加了参数校验注解,但是不会生效
  • 需要自定义一个list集合来接收参数,并使用@Delegate注解(可以不用手动重写父类方法)
  • 校验失败会抛出NotReadablePropertyException异常,如果全局异常拦截,,却无法获取哪个字段参数校验失败;栗子没有拦截
public class ValidationList<E> implements List<E> 

    @Delegate // @Delegate是lombok注解 ,1.18.6以上版本可支持
    @Valid // 一定要加@Valid注解
    public List<E> list = new ArrayList<>();

    // 一定要记得重写toString方法
    @Override
    public String toString() 
        return list.toString();
    

3.3. 非实体类集合参数校验:


3.4. 分组校验:

  • 不同场景共用同一个实体类,而且校验规则不一样,这时可以使用分组校验
  • 使用时,在对于的注解加上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;

    @Valid
    private Job job;

    @Data
    public 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 实现接口的各种参数校验

以上是关于Hibernate-Validator 接口参数校验 | 嵌套参数校验的主要内容,如果未能解决你的问题,请参考以下文章

hibernate-validator验证请求参数

Java:SpringBoot整合hibernate-validator实现入参数据校验

SpringBoot整合Hibernate-Validator校验器

SpringBoot整合Hibernate-Validator校验器

hibernate-validator校验参数(统一异常处理)

Hibernate-Validator框架完成服务端参数据校验(巨详细)