• JRS303-数据校验


    🧑‍🎓 个人主页:花棉袄

    📖 本章内容:【JRS303-数据校验
    ✍🏻 版权: 本文由【花棉袄】原创💝在CSDN首发💝需要转载请联系博主

    在这里插入图片描述

    🌳 JRS303-数据校验🌳

    📢💨如果文章对你有帮助【关注👍点赞❤️收藏⭐】

    🥙JSR303介绍

    • 在Java中提供了一系列的校验方式
    • 这些校验方式在“javax.validation.constraints”包中
    • 提供了如@Email,@NotNull等注解

    1️⃣引入依赖

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-validationartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 在非空处理方式上提供了@NotNull,@NotBlank和@NotEmpty

    2️⃣常用注解

    • 所有校验注解都在:javax.validation.constraints包下

    🌳 @NotNull

    • 注解元素禁止为null,能够接收任何类型

    🌳 @NotEmpty

    • 该注解修饰的字段不能为null或""
    • 支持以下几种类型
    集合长度的计算
    Map (map size is evaluated)
    map长度的计算
    Array (array length is evaluated)
    数组长度的计算
    
    • 1
    • 2
    • 3
    • 4
    • 5

    🌳 @NotBlank

    • 该注解不能为null,并且至少包含一个非空格字符
    • 接收字符序列

    3️⃣开启校验

    🌳 @Valid

    • controller中加校验注解@Valid,开启校验

    🥌数据校验测试

    • 步骤1:实体类字段上使用校验注解 @NotNull @NotEmpty @NotBlank @Pattern
    • 步骤2:controller中加校验注解@Valid,开启校验
    • 步骤3:给校验的Bean后,紧跟一个BindResult,就可以获取到校验的结果,拿到校验的结果,就可以自定义的封装
    public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){}
    
    • 1
    • 实体中添加注解
    @Data
    public class Student {
        @NotEmpty(message ="姓名不能为空")
        private String name;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • controller层中保存方法添加:@Valid
    @RestController
    public class TestController {
        @RequestMapping("/test")
        public Result test(@Valid  @RequestBody Student student, BindingResult result) {
            String name = student.getName();
            HashMap<String, Object> map = new HashMap<>();
            map.put("name",name);
            map.put("errors",result.getFieldErrors());
             return Result.ok(map,"数据校验");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 📢🌥️ 测试:http://localhost:8080/test
    {
        "name":""
    }
    
    • 1
    • 2
    • 3
    • 📢🌥️ 返回信息
    {
    	"code": 200,
    	"msg": "数据校验",
    	"data": {
    		"name": "",
    		"errors": [
    			{
    				"codes": [
    					"NotEmpty.student.name",
    					"NotEmpty.name",
    					"NotEmpty.java.lang.String",
    					"NotEmpty"
    				],
    				"arguments": [
    					{
    						"codes": [
    							"student.name",
    							"name"
    						],
    						"arguments": null,
    						"defaultMessage": "name",
    						"code": "name"
    					}
    				],
    				"defaultMessage": "姓名不能为空",
    				"objectName": "student",
    				"field": "name",
    				"rejectedValue": "",
    				"bindingFailure": false,
    				"code": "NotEmpty"
    			}
    		]
    	}
    }
    
    • 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

    1️⃣自定义的封装错误信息

    @RestController
    public class TestController {
        @RequestMapping("/test")
        public Result test(@Valid @RequestBody Student student, BindingResult result) {
            String name = student.getName();
            Map<String, String> map = new HashMap<>();
            map.put("name", name);
            if (result.hasErrors()) {
                //1.获取错误的校验结果
                result.getFieldErrors().forEach((item) -> {
                    //2.获取发生错误时的message
                    String message = item.getDefaultMessage();
                    //3.获取发生错误的字段
                    String field = item.getField();
                    map.put(field, message);
                });
                return Result.fail(map, "数据校验");
            } else {
                return Result.ok(map);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 📢🌥️ 测试:http://localhost:8080/test
    {
        "name":""
    }
    
    • 1
    • 2
    • 3
    • 📢🌥️ 错误信息
    {
    	"code": 500,
    	"msg": "数据校验",
    	"data": {
    		"name": "姓名不能为空"	
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2️⃣统一异常处理

    • springmvc统一处理异常
    @Slf4j
    @RestControllerAdvice(basePackages = "com.michale.jrs303.controllers")
    public class FireflyMallExceptionControllerAdvice {
        /**
         * 处理数据校验问题
         * @param e
         * @return
         */
        @ExceptionHandler(value = MethodArgumentNotValidException.class)
        public Result handleVaildException(MethodArgumentNotValidException e) {
            log.error("数据校验出现问题:{},异常类型:{}", e.getMessage(), e.getClass());
            BindingResult bindingResult = e.getBindingResult();
            Map<String, String> errorMap = new HashMap();
            bindingResult.getFieldErrors().forEach((fieldError) -> {
                errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
    
            });
            return Result.fail(errorMap, "数据校验出现问题");
        }
    
        /**
         * 处理其他异常
         * @param throwable
         * @return
         */
        @ExceptionHandler(value = Throwable.class)
        public Result handleException(Throwable throwable) {
            return Result.fail();
        }
    }
    
    
    • 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
        @RequestMapping("/testException")
        public Result testException(@Valid @RequestBody Student student) {
            String name = student.getName();
            Map<String, String> map = new HashMap<>();
            map.put("name", name);
            return Result.ok(map);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 📢🌥️ 测试统一异常处理:测试:http://localhost:8080/testException
    {
        "name":"",
    }
    
    • 1
    • 2
    • 3
    • 📢🌥️ 错误信息
    {
    	"code": 500,
    	"msg": "数据校验出现问题",
    	"data": {
    		"name": "姓名不能为空"
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    🍖JSR303分组校验

    1️⃣创建分组校验接口

    /**
     * @Author 天才小狐狸
     * @Data 2022/8/11 2:03
     * @Description 姓名校验分组
     */
    public interface NameGroup {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    /**
     * @Author 天才小狐狸
     * @Data 2022/8/11 2:04
     * @Description 年龄校验分组
     */
    public interface AgeGroup {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2️⃣添加校验注解

    @Data
    public class Student {
        @NotEmpty(message ="姓名不能为空",groups =  NameGroup.class)
        private String name;
    
        @NotEmpty(message ="绰号不能为空",groups = NameGroup.class)
        private  String nickName;
    
        @Min(value = 18,message = "年龄下限不能低于18岁" ,groups = AgeGroup.class)
        private String age;
    
        @Max(value = 60,message = "年龄上限不能超过60岁" ,groups = AgeGroup.class)
        private  String retireAge;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3️⃣开启分组校验

    • @Validated(NameGroup.class)指定校验分组
    @RequestMapping("/testGroup")
        public Result testGroup(@Validated(NameGroup.class) @RequestBody Student student) {
            String name = student.getName();
            String nickName = student.getNickName();
            String age = student.getAge();
            String retireAge = student.getRetireAge();
            Map<String, String> map = new HashMap<>();
            map.put("name", name);
            map.put("nickname", nickName);
            map.put("age", age);
            map.put("retireAge", retireAge);
            return Result.ok(map);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 📢🌥️ 测试分组校验:http://localhost:8080/testGroup
    {
        "name":"",
        "nickName":"",
        "age":"17",
        "retireAge":"66"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 📢🌥️ 错误信息
    {
    	"code": 500,
    	"msg": "数据校验出现问题",
    	"data": {
    		"nickName": "绰号不能为空",
    		"name": "姓名不能为空"
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • @Validated(AgeGroup.class)指定校验分组
    @RequestMapping("/testGroup")
        public Result testGroup(@Validated(AgeGroup.class) @RequestBody Student student) {
            String name = student.getName();
            String nickName = student.getNickName();
            String age = student.getAge();
            String retireAge = student.getRetireAge();
            Map<String, String> map = new HashMap<>();
            map.put("name", name);
            map.put("nickname", nickName);
            map.put("age", age);
            map.put("retireAge", retireAge);
            return Result.ok(map);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 📢🌥️ 测试分组校验:http://localhost:8080/testGroup
    {
        "name":"",
        "nickName":"",
        "age":"17",
        "retireAge":66
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 📢🌥️ 错误信息
    {
    	"code": 500,
    	"msg": "数据校验出现问题",
    	"data": {
    		"retireAge": "年龄上限不能超过60岁",
    		"age": "年龄下限不能低于18岁"
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    🥙JSR303自定义校验

    1️⃣编写自定义的校验注解

    • 比如要创建一个:@ListValue 注解,被标注的字段值只能是:0或1
    @Documented
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    public @interface ListValue {
        // 使用该属性去Validation.properties中取
        String message() default "{com.atguigu.common.valid.ListValue.message}";
    
        Class<?>[] groups() default { };
    
        Class<? extends Payload>[] payload() default { };
    
        int[] value() default {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 设置错误信息:创建文件ValidationMessages.properties
     com.firefly.common.valid.ListValue.message=必须提交指定的值 [0,1]
    
    • 1

    2️⃣编写自定义的校验器

    
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * @author Michale @EMail:firefly@163.com
     * @Date: 2022/1/8 19:23
     * @Name ListValueConstraintValidator
     * @Description:
     */
    public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
        private Set<Integer> set = new HashSet<>();
    
        @Override
        public void initialize(ListValue constraintAnnotation) {
            //获取注解允许的值
            int[] value = constraintAnnotation.value();
            for (int i : value) {
                set.add(i);
            }
        }
    
        @Override
        public boolean isValid(Integer value, ConstraintValidatorContext context) {
            //判断传入的值是否在满足允许的值
            boolean b = set.contains(value);
            return b;
        }
    }
    
    • 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

    3️⃣关联校验器和校验注解

    • 在@ListValue注解关联校验器
    @Constraint(validatedBy = { ListValueConstraintValidator.class})
    一个校验注解可以匹配多个校验器
    
    • 1
    • 2

    4️⃣添加自定义的校验注解

        @ListValue(value = {0,1},groups = {AgeGroup.class,MyJRS303Group.class})
        private Integer gender;
    
    • 1
    • 2
    • 📢🌥️ 测试自定义校验器:http://localhost:8080/testGroup
    {
        "gender":"3"
    }
    
    • 1
    • 2
    • 3
    {
    	"code": 500,
    	"msg": "数据校验出现问题",
    	"data": {
    		"gender": "必须提交指定的值 [0,1]"
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    容器服务(三)自动化监控 Prometheus、Grafana
    Boot 和 Cloud 的版本选型
    22款奔驰GLE450升级香氛负离子 清新淡雅
    golang学习笔记——类型转换
    【Linux】从零开始学习Linux基本指令(二)
    【环境】Linux下Anaconda/ Miniconda安装+百度Paddle环境搭建+Cudnn(3090显卡+CUDA11.8+cudnn8.6.0)
    MTK system_server 卡死导致手机重启案例分析
    Redis的介绍以及简单使用连接池
    大数据docker部署
    深度学习| 注意力机制
  • 原文地址:https://blog.csdn.net/m0_46914264/article/details/126276710