zoukankan      html  css  js  c++  java
  • 学习Validator验证框架总结

    在项目开发中许多地方需要加以验证,对于使用if-else简单粗暴一个一个验证,spring的validation封装了Javax ValidationI校验参数,大大缩减了代码量。

    以前的分层验证,从controller到落入数据库,一层一层验证,代码重复、冗余。

    Javax ValidationI使用Java Bean验证通过注解将约束添加到域模型中,将验证逻辑从代码中分离出来。

    Javax ValidationI的依赖:

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>2.0.1.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.16.Final</version>
     </dependency>
    

      

    springboot对Javax ValidationI封装,依赖变成

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

     一、初级注解

    JSR提供的验证注解:

    @Null   被注释的元素必须为 null    

    @NotNull    被注释的元素必须不为 null    

    @AssertTrue     被注释的元素必须为 true    

    @AssertFalse    被注释的元素必须为 false    

    @Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值   &nbsp

    @Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值    

    @DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值    

    @DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值    

    @Size(max=, min=)   被注释的元素的大小必须在指定的范围内    

    @Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内    

    @Past   被注释的元素必须是一个过去的日期    

    @Future     被注释的元素必须是一个将来的日期    

    @Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式

    Validator提供的验证注解:

    @NotBlank(message =)   验证字符串非null,且长度必须大于0    

    @Email  被注释的元素必须是电子邮箱地址    

    @Length(min=,max=)  被注释的字符串的大小必须在指定的范围内    

    @NotEmpty   被注释的字符串的必须非空    

    @Range(min=,max=,message=)  被注释的元素必须在合适的范围内

    二、创建验证器

    /**
     * 验证测试类
     */
    public class ValidationTest {
    
        // 验证器对象
        private Validator validator;
        // 待验证对象
        private UserInfo userInfo;
        // 验证结果集合
        private Set<ConstraintViolation<UserInfo>> set;
    
        /**
         * 初始化操作
         */
        @Before
        public void init() {
            // 初始化验证器
            validator = Validation.buildDefaultValidatorFactory()
                    .getValidator();
    
            // 初始化待验证对象 - 用户信息
            userInfo = new UserInfo();
    
        }
    
        /**
         * 结果打印
         */
        @After
        public void print() {
            set.forEach(item -> {
                // 输出验证错误信息
                System.out.println(item.getMessage());
            });
    
        }
    
        @Test
        public void nullValidation() {
            // 使用验证器对对象进行验证
            set = validator.validate(userInfo);
        }
    
    }
    

      三、中级约束

        中级约束中分为分组约束、组序列

    public class UserInfo {
    
        // 登录场景
        public interface LoginGroup {}
    
        // 注册场景
        public interface RegisterGroup {}
    
        /**
         * 用户ID
         */
        @NotNull(message = "用户ID不能为空",
                groups = LoginGroup.class)
        private String userId;
    
        /**
         * 用户名
         * NotEmpty 不会自动去掉前后空格
         */
        @NotEmpty(message = "用户名称不能为空",groups = RegisterGroup.class)
        private String userName;
    
        /**
         * 用户密码
         * NotBlank 自动去掉字符串前后空格后验证是否为空
         */
        @NotBlank(message = "用户密码不能为空")
        @Length(min = 6, max = 20,
                message = "密码长度不能少于6位,多于20位")
        private String passWord;
    
    }
    

      

      /**
         * 分组验证测试方法
         */
        @Test
        public void groupValidation() {
            set = validator.validate(userInfo,
                    UserInfo.RegisterGroup.class,
                    UserInfo.LoginGroup.class);
        }
    

      组排序:

    public class UserInfo {
    
        // 登录场景
        public interface LoginGroup {}
    
        // 注册场景
        public interface RegisterGroup {}
    
        // 组排序场景
        @GroupSequence({
                LoginGroup.class,
                RegisterGroup.class,
                Default.class
        })
        public interface Group {}
    
        /**
         * 用户ID
         */
        @NotNull(message = "用户ID不能为空",
                groups = LoginGroup.class)
        private String userId;
    
        /**
         * 用户名
         * NotEmpty 不会自动去掉前后空格
         */
        @NotEmpty(message = "用户名称不能为空", 
                groups = RegisterGroup .class)
        private String userName;
    
        /**
         * 用户密码
         * NotBlank 自动去掉字符串前后空格后验证是否为空
         */
        @NotBlank(message = "用户密码不能为空")
        @Length(min = 6, max = 20,
                message = "密码长度不能少于6位,多于20位")
        private String passWord;
    }    
    

      

        /**
         * 组序列测试
         */
        @Test
        public void groupSequenceValidation() {
            set = validator.validate(userInfo,
                    UserInfo.Group.class);
        }
    

      三、高级约束

        高级约束是对参数、返回值的约束。

        使用注解:

          javax:@Valid

          spring:@Validated

        在检验参数、返回值是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同。

        @Validated:提供了一个分组功能,可以在入参、返回值验证时,根据不同的分组采用不同的验证机制。

        @Valid:不支持分组功能。

        注解地方:

        @Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上。

        @Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上。

    /**
     * 用户信息
     */
    public class UserInfoService {
    
        /**
         * UserInfo 作为输入参数
         * @param userInfo
         */
        public void setUserInfo(@Valid UserInfo userInfo) {}
    
        /**
         * UserInfo 作为输出参数
         * @return
         */
        public @Valid UserInfo getUserInfo() {
            return new UserInfo();
        }
    
    }
    

      

    /**
     * 验证测试类
     */
    public class ValidationTest {
    
        // 验证器对象
        private Validator validator;
        // 待验证对象
        private UserInfo userInfo;
        // 验证结果集合
        private Set<ConstraintViolation<UserInfoService>> otherSet;
    
        /**
         * 初始化操作
         */
        @Before
        public void init() {
            // 初始化验证器
            validator = Validation.buildDefaultValidatorFactory()
                    .getValidator();
    
            // 初始化待验证对象 - 用户信息
            userInfo = new UserInfo();
        }
    
        /**
         * 结果打印
         */
        @After
        public void print() {
            set.forEach(item -> {
                // 输出验证错误信息
                System.out.println(item.getMessage());
            });
    
        }
    
    
        /**
         * 对方法输入参数进行约束注解校验
         */
        @Test
        public void paramValidation() throws NoSuchMethodException {
            // 获取校验执行器
            ExecutableValidator executableValidator =
                    validator.forExecutables();
    
            // 待验证对象
            UserInfoService service = new UserInfoService();
            // 待验证方法
            Method method = service.getClass()
                    .getMethod("setUserInfo", UserInfo.class);
            // 方法输入参数
            Object[] paramObjects = new Object[]{new UserInfo()};
    
            // 对方法的输入参数进行校验
            otherSet = executableValidator.validateParameters(
                    service,
                    method,
                    paramObjects);
        }
    
    
        /**
         * 对方法返回值进行约束校验
         */
        @Test
        public void returnValueValidation()
                throws NoSuchMethodException,
                InvocationTargetException, IllegalAccessException {
    
            // 获取校验执行器
            ExecutableValidator executableValidator =
                    validator.forExecutables();
    
            // 构造要验证的方法对象
            UserInfoService service = new UserInfoService();
            Method method = service.getClass()
                    .getMethod("getUserInfo");
    
            // 调用方法得到返回值
            Object returnValue = method.invoke(service);
    
            // 校验方法返回值是否符合约束
            otherSet = executableValidator.validateReturnValue(
                    service,
                    method,
                    returnValue);
        }
    
    }
    

      在controller中验证入参一般使用@Validated

    @RequestMapping(method = RequestMethod.POST)
        public UserInfo  create(@RequestBody @Validated( { RegisterGroup.class }) UserInfo  userInfo) {
    		return userService.create(userInfo);
        }
    
      @RequestMapping(method = RequestMethod.GET)
        public UserInfo  getUserById(@NotNull(message = "id不能为空")  int userId)  {
           return userService.getUserById(userId);
        }
    

      四、自定义约束注解

    /**
     * 自定义手机号约束注解
     */
    @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 {};
    }
    

      

    /**
     * 自定义手机号约束注解关联验证器
     */
    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();
        }
    }
    

      自定义注解使用:

    public class UserInfo{
        /**
         * 手机号
         */
        @Phone(message = "手机号不是158后头随便")
        private String phone;
    }
    

      

  • 相关阅读:
    1 slow requests are blocked > 32 sec解决方法
    centos7下搭建ceph luminous(12.2.1)--无网或网络较差
    防止集群数据恢复设置
    ceph:health_warn clock skew detected on mon的解决办法
    Windows下判断jdk是否安装好以及环境变量是否配置好
    卸载Myeclipse10.5 报错“an error has occured.See the log file ...Uninstaller...”
    转: Laravel 自定义公共函数的引入
    windows下安装composer
    PHP与.Net的区别(一)接口
    phpStorm+XDebug配置
  • 原文地址:https://www.cnblogs.com/dinghaoran/p/12924518.html
Copyright © 2011-2022 走看看