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


    0. 依赖:

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

    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-validationartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1. 常用注解:

    来源https://blog.csdn.net/ye___li/article/details/107512099

    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());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    【接口方法】:

        @PostMapping("/save")
        public BaseResponse saveUser(@RequestBody @Validated UserDTO userDTO) {
            // 校验通过,才会执行业务逻辑处理
            return BaseResponse.SUCCESS();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    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 {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    【举个栗子】:添加时userId允许为空,更新时不允许为空

    在这里插入图片描述

    在这里插入图片描述

    原理和更多内容可以查看参考链接二

    【参考链接】:
    ·
     参考一:Hibernate Validator 参数验证 单个实体类与List集合的验证
     参考二:SpringBoot 实现接口的各种参数校验

  • 相关阅读:
    flink-sql所有语法详解-1.16
    Opencv项目实战:14 手势控制音量
    10-27 maven概念
    leetcode 6103 — 从树中删除边的最小分数
    自然语言处理学习笔记-lecture06-词法分析与词性标注
    Prometheus-部署grafana及模板展示
    ES6扩展运算符(...)
    WPF行为
    复习计算机网络——第二章记录(2)
    利用多线程和queue实现生产-消费者模式--消息队列
  • 原文地址:https://blog.csdn.net/weixin_43901882/article/details/127826462