• 优雅的使用Validated


    前言

    @Validation是一套帮助我们继续对传输的参数进行数据校验的注解,通过配置Validation可以很轻松的完成对数据的约束。
    这个技术一直都想进行梳理了很多复杂校验不会使用,本章节用来进行梳理
    validated 用于参数的校验,支持简单和复杂(分组/嵌套)校验
    
    • 1
    • 2
    • 3

    @Validated / @Valid 的区别

    功能
    	@validated 提供了分组能力而@Valid没有
    位置
    	@Valid作用于 方法\构造方法\方法参数\成员属性
    	@Validdated作用于  类\方法\方法参数
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意事项

    可能不生效的几个原因:
    	1. @validate 默认将所有校验加入到了Default组中,如果指定了自定义组将不会校验Default组中的校验,如果需要校验默认组需要加上Default组,面对复杂的校验很有可能会搞混
    	2. 如果需要使用分组,那么定义分组类型需要是接口类型,否则会报错~~
    	3. 如果使用了正则校验查看 正则是否正确
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注解

    在这里插入图片描述

    逻辑图

    Validatad 工作机制描述
    调用者发送请求后端 -> Validatad拦截器将请求体进行拦截后校验 
    	-> 校验成功 -> 通过
    	-> 校验失败 -> 抛出异常  -> 对异常进行处理(通过@RestControllerAdvice + @ExceptionHandler 注解进行异常处理)
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    依赖

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

    校验

    目前有关于商品的接口需要进行校验
    
    • 1

    异常的处理

    import org.springframework.validation.BindingResult;
    import org.springframework.validation.FieldError;
    import org.springframework.validation.ObjectError;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import java.util.List;
    
    @RestControllerAdvice
    public class MyControllerAdvice {
        
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public String exceptionHandler(MethodArgumentNotValidException exception) {
            BindingResult result = exception.getBindingResult();
            StringBuilder stringBuilder = new StringBuilder();
            if (result.hasErrors()) {
                List<ObjectError> errors = result.getAllErrors();
                if (errors != null) {
                    errors.forEach(p -> {
                        FieldError fieldError = (FieldError) p;
                        stringBuilder.append(fieldError.getDefaultMessage());
                    });
                }
            }
            return stringBuilder.toString();
        }
    }
    
    • 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

    简单校验

    目前商品添加了一个新增接口需要进行校验
    校验内容:
    	商品的名称不能为空
    
    • 1
    • 2
    • 3
    import lombok.Data;
    import lombok.experimental.Accessors;
    import javax.validation.constraints.Min;
    import javax.validation.constraints.NotEmpty;
    
    @Data
    @Accessors(chain = true)
    public class MyTestDTO {
        @NotEmpty(message = "产品名称不能为空")
        private String product;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    @RestController
    @RequestMapping("api")
    public class MyController {
        @PostMapping("addProduct")
        public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {
            return myTestDTO;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    分组校验

    分组: 如果在Controller中设置了分组,那么校验的时候只会走对应的分组拦截器,默认没有分组的校验都在javax.validation.groups.Default.class组中
    
    目前关于商品又增加了一个删除的接口原限制不变
    	新增接口:
    		产品名称不能为空
    	修改接口:
    		产品名称长度不能超过10位
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //定义分组接口
    public interface Group1 { //新增商品的分组
    }
    public interface Group2 { //修改商品的分组
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    import com.chen.advice.Group1;
    import com.chen.advice.Group2;
    import com.chen.pojo.MyTestDTO;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping("api")
    public class MyController {
        @PostMapping("addProduct")
        public MyTestDTO addProduct(@RequestBody @Validated(Group1.class) MyTestDTO myTestDTO) {
            return myTestDTO;
        }
    
        @PutMapping("putProduct")
        public MyTestDTO putProduct(@RequestBody @Validated(Group2.class) MyTestDTO myTestDTO) {
            return myTestDTO;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    import com.chen.advice.Group1;
    import com.chen.advice.Group2;
    import lombok.Data;
    import lombok.experimental.Accessors;
    import javax.validation.constraints.Min;
    import javax.validation.constraints.NotEmpty;
    import javax.validation.constraints.Size;
    
    @Data
    @Accessors(chain = true)
    public class MyTestDTO {
        @NotEmpty(message = "产品名称不能为空",groups = Group1.class)
        @Size(max = 10,message = "产品名称长度不能超过10位",groups = Group2.class)
        private String product;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述
    在这里插入图片描述

    嵌套校验

    	注意事项:
    		嵌套校验:  对象中的对象属性需要加上@valid的注解
    
    • 1
    • 2
    import lombok.Data;
    import lombok.experimental.Accessors;
    import javax.validation.Valid;
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Size;
    
    @Data
    @Accessors(chain = true)
    public class MyTestDTO {
        @Size(max = 10,message = "产品名称长度不能超过10位")
        private String product;
    
        @Valid
        @NotNull(message = "医疗实体类不能为null")
        private YiLiaoDTO yiLiaoDTO;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    import lombok.Data;
    import javax.validation.constraints.Positive;
    
    @Data
    public class YiLiaoDTO {
        @Positive(message = "产品数量必须为正整数")
        private Integer count;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    import com.chen.pojo.MyTestDTO;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping("api")
    public class MyController {
        @PostMapping("addProduct")
        public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {
            return myTestDTO;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    注解的尝试

    自定义注解校验

    注解类 -- 模仿自带的注解类进行编写
    @Constraint(validateBy = 指定配置类)
    
    • 1
    • 2
    @Target({ElementType.METHOD,ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = MyValidCheck.class)
    public @interface MyValid {
        int min() default  0;
        String message() default "{javax.validation.constraints.Size.message}";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    配置类
    initalize() 初始化方法用于获取注解设置的值
    isValid() 判断是否通过校验
    
    • 1
    • 2
    • 3
    import com.example.demo.annotation.MyValid;
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    
    public class MyValidCheck implements ConstraintValidator<MyValid,Object> {
        int min ;
        @Override
        public void initialize(MyValid constraintAnnotation) {
             min = constraintAnnotation.min();
        }
        @Override
        public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
            if (o != null && o.toString().length() <= min) {
                return true;
            }
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    Controller类
    
    • 1
    @RestController
    @RequestMapping("api")
    public class MyController {
        @PostMapping("addProduct")
        public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {
            return myTestDTO;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    import com.example.demo.annotation.MyValid;
    import lombok.Data;
    
    @Data
    public class MyTestDTO {
        private String id;
        private String product;
        @MyValid(min =  10,message = "你小子不按规则走呀,输入10位以内")
        private Integer size;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    正则校验

    @Pattern(regexp = "^[A-Za-z0-9]+$",message = "不符合正则规定了哦小伙子")
    private String name;
    
    • 1
    • 2

    特殊校验

    校验List<对象>

    // 自行封装一个 List 没有经过尝试
    @***Mapping("/**")
    public *** apiName(@RequestBody @Validated(Add.class) ValidList<Bean> aObject)
    
    • 1
    • 2
    • 3
    package com.analog.greatbolderserver.config.valid;
     
    import lombok.Data;
    import lombok.NoArgsConstructor;
     
    import javax.validation.Valid;
    import java.util.*;
     
    /**
     * @ClassName ValidList
     * @Description ValidList
     * @Author TY
     * @Date 2020/8/26 16:05
     * @Version 1.0
     **/
    @Data
    @NoArgsConstructor
    public class ValidList<E> implements List<E> {
     
        @Valid
        private List<E> list = new LinkedList<>();
     
        public ValidList(List<E> paramList) {
            this.list = paramList;
        }
     
        @Override
        public int size() {
            return list.size();
        }
     
        @Override
        public boolean isEmpty() {
            return list.isEmpty();
        }
     
        @Override
        public boolean contains(Object o) {
            return list.contains(0);
        }
     
        @Override
        public Iterator<E> iterator() {
            return list.iterator();
        }
     
        @Override
        public Object[] toArray() {
            return list.toArray();
        }
     
        @Override
        public <T> T[] toArray(T[] a) {
            return list.toArray(a);
        }
     
        @Override
        public boolean add(E e) {
            return list.add(e);
        }
     
        @Override
        public boolean remove(Object o) {
            return list.remove(o);
        }
     
        @Override
        public boolean containsAll(Collection<?> c) {
            return list.containsAll(c);
        }
     
        @Override
        public boolean addAll(Collection<? extends E> c) {
            return list.addAll(c);
        }
     
        @Override
        public boolean addAll(int index, Collection<? extends E> c) {
            return list.addAll(index, c);
        }
     
        @Override
        public boolean removeAll(Collection<?> c) {
            return list.removeAll(c);
        }
     
        @Override
        public boolean retainAll(Collection<?> c) {
            return list.retainAll(c);
        }
     
        @Override
        public void clear() {
            list.clear();
        }
     
        @Override
        public E get(int index) {
            return list.get(index);
        }
     
        @Override
        public E set(int index, E element) {
            return list.set(index, element);
        }
     
        @Override
        public void add(int index, E element) {
            list.add(index, element);
        }
     
        @Override
        public E remove(int index) {
            return list.remove(index);
        }
     
        @Override
        public int indexOf(Object o) {
            return list.indexOf(o);
        }
     
        @Override
        public int lastIndexOf(Object o) {
            return list.lastIndexOf(o);
        }
     
        @Override
        public ListIterator<E> listIterator() {
            return list.listIterator();
        }
     
        @Override
        public ListIterator<E> listIterator(int index) {
            return list.listIterator(index);
        }
     
        @Override
        public List<E> subList(int fromIndex, int toIndex) {
            return list.subList(fromIndex, toIndex);
        }
    }
    
    • 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
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
  • 相关阅读:
    R语言编写switch函数进行多分支选择、判断编程:使用switch函数在多种方案中进行选择
    ERROR in docs.42140ac.js from UglifyJs webpack打包报错
    springboot链接mongodb采用SSL方式
    如何运营一个微信公众号?
    产品思维训练 | 如何有效提高问答网站中的问题回复率?
    PyTorch深度学习框架
    【vue3】消息的订阅与发布
    Synchronized 原 理
    虚拟局域网
    GDPU 数据结构 天码行空3
  • 原文地址:https://blog.csdn.net/qq_41149775/article/details/126172137