• spring-boot 请求参数校验:注解 @Validated 的使用、手动校验、自定义校验


    前言

    spring-boot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。
    spring-boot已经引入了基础包,所以直接使用就可以。

    注解 @validated 的使用

    @RestController
    @Validated
    public class LoginController {
        /**
         * 登录接口
         * @return
         */
        @PostMapping("login")
        public String login(@Length(min = 6, max = 12, message = "密码长度必须在6位到12位之间")String pwd) {
            return "ok";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    注解 @validated 校验参数类

    在属性上添加校验注解:

    import org.hibernate.validator.constraints.Length;
    import javax.validation.constraints.*;
    
    public class User {
    
        @NotBlank(message = "用户名不能为null,长度必须大于0")
        String name;   //用户名
    
        @Min(value = 1, message = "最小年龄为1岁")
        @Max(value = 120, message = "最大年龄为120岁")
        Integer age;  //年龄
    
        @Email(message = "邮箱格式错误")
        @NotBlank(message = "邮箱必填")
        @Size(min = 6, max = 50, message = "邮箱长度必须在6位到50位之间")
        String email;  //邮箱
    
        @Length(min = 6, max = 12, message = "密码长度必须在6位到12位之间")
        String pwd;//密码
        
        //...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在Controller上添加 @Validated 注解

        /**
         * 登录接口
         * @return
         */
        @PostMapping("login")
        public String login(@Validated @RequestBody User user) {
            return "ok";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    校验未通过时,可能看到:

    {
      "msg": "邮箱格式错误",
      "code": 500
    }
    
    • 1
    • 2
    • 3
    • 4

    可用的校验注解

    JSR提供的校验注解:         
    @Null   被注释的元素必须为 null    
    @NotNull    被注释的元素必须不为 null,不能为 null , 可以为 ""    
    @AssertTrue     被注释的元素必须为 true    
    @AssertFalse    被注释的元素必须为 false    
    @Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
    @Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
    @DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
    @DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
    @Size(max=, min=)   验证对象(Array,Collection,Map,String)长度是否在给定的范围之内    
    @Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内    
    @Past   被注释的元素必须是一个过去的日期    
    @Future     被注释的元素必须是一个将来的日期    
    @Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式    
    
    Hibernate Validator提供的校验注解:  
    @NotBlank(message =)   只能作用在String上,不能为null,而且调用trim()后,长度必须大于0    
    @Email  被注释的元素必须是电子邮箱地址    
    @Length(min=,max=)  被注释的字符串的大小必须在指定的范围内    
    @NotEmpty   被注释的字符串的必须非空,不能为 null、"",可以为 " "    
    @Range(min=,max=,message=)  被注释的元素必须在合适的范围内
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    手动处理错误

    @Validated后面紧跟着追加BindingResult,可接管检验后的处理(处理校验出来的错误):

      /**
         * 登录接口
         *
         * @return
         */
        @PostMapping("login")
        public String login(@Validated @RequestBody User user, BindingResult bindingResult) {
            if (bindingResult.hasErrors()) {
                //有校验没通过
                List<ObjectError> errorList = bindingResult.getAllErrors();
                for (ObjectError error : errorList) {
                    System.out.println(error.getDefaultMessage());  //输出具体的错误信息
                }
                return "参数异常";
            }
            return "ok";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    嵌套校验

    如果一个类中包含了另外一个实体类,那么在上面加上@Validated即可,比如上面的

     public class User {    
        @validated
        private Dept dept;
     }
    
    • 1
    • 2
    • 3
    • 4

    @pathvariable的校验

    暂不支持

    手动校验

        /**
         * 登录接口
         * @return
         */
        @PostMapping("login")
        public String login(@RequestBody User user) {
    	    ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
    		Validator validator = vf.getValidator();
    		Set<ConstraintViolation<User>> set = validator.validate(user);
    		for (ConstraintViolation<User> constraintViolation : set) {
    		    System.out.println(constraintViolation.getMessage());
    		}
            return "ok";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    自定义约束注解

    自定义约束注解:

    /**
     * 自定义手机号约束注解
     */
    @Documented
    // 注解的作用目标
    @Target({ElementType.FIELD})
    // 注解的保留策略
    @Retention(RetentionPolicy.RUNTIME)
    // 不同之处:于约束注解关联的验证器
    @Constraint(validatedBy = PhoneValidator.class)
    public @interface Phone {
     
        // 约束注解验证时的输出信息
        String message() default "手机号校验错误";
     
        // 约束注解在验证时所属的组别
        Class<?>[] groups() default {};
     
        // 约束注解的有效负载(严重程度)
        Class<? extends Payload>[] payload() default {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    真正的校验者类:

    /**
     * 自定义手机号约束注解关联验证器
     */
    public class PhoneValidator
            implements ConstraintValidator<Phone, String> {
     
        /**
         * 自定义校验逻辑方法
         * @param value
         * @param context
         * @return
         */
        @Override
        public boolean isValid(String value,
                               ConstraintValidatorContext context) {
     
            // 手机号验证规则:158后头随便
            String check = "158\\d{8}";
            Pattern regex = Pattern.compile(check);
     
            // 空值处理
            String phone = Optional.ofNullable(value).orElse("");
            Matcher matcher = regex.matcher(phone);
     
            return matcher.matches();
        }
    }
    
    • 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

    自定义注解使用:

    public class User{
        /**
         * 手机号
         */
        @Phone(message = "手机号不是158后头随便")
        private String phone;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    手动校验时,自定义注解使用:

    Configuration config = Validation.byProvider(PhoneValidator.class).configure();   
    ValidatorFactory vf = config.buildValidatorFactory();   
    Validator validator = vf.getValidator();  
    
    • 1
    • 2
    • 3

    参考

    https://docs.spring.io/spring-framework/docs/5.0.6.RELEASE/spring-framework-reference/core.html#validation-beanvalidation
    https://docs.spring.io/spring-framework/docs/5.0.6.RELEASE/spring-framework-reference/web.html#mvc-config-validation
    https://docs.spring.io/spring-boot/docs/2.2.13.RELEASE/reference/htmlsingle/#boot-features-validation
    https://www.cnblogs.com/zhaoyanjun/p/9007056.html
    https://www.cnkirito.moe/spring-validation/
    https://www.cnblogs.com/dinghaoran/p/12924518.html
    https://www.jianshu.com/p/b3876bf9396c
    https://blog.csdn.net/zhu_tianwei/article/details/43272181

  • 相关阅读:
    5.1、nio-Bytebuffer内存结构
    Django 入门学习总结7-静态文件管理
    java字符串转数字
    一张图看懂 SQL 的各种 join 用法!
    【web自动化测试】Playwright快速入门,5分钟上手
    hive 常用函数
    硅谷并购中的牙刷测试
    FPGA/IC秋招面试题 1(解析版)
    Java数据结构与Java算法学习Day02---算法排序
    你要有自己的影响力
  • 原文地址:https://blog.csdn.net/sayyy/article/details/128043459