hibernate validation

hibernate validation

1. pom.xml配置

    <properties>
        <java.version>1.8</java.version>
        <javax-validation.version>2.0.1.Final</javax-validation.version>
        <hibernate-validator.version>6.1.5.Final</hibernate-validator.version>
        <javax.el.version>3.0.0</javax.el.version>
    </properties>
    <dependencies>
        <!-- validation -->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>${javax-validation.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>${hibernate-validator.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>${javax.el.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.el</artifactId>
            <version>${javax.el.version}</version>
        </dependency>
    </dependencies>

2. validation加载原理

这里使用的技术是  SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务的实现。

在这里服务会寻找实现上图最后一个红框内javax.validation.spi.ValidationProvider这个接口的类。在存在一个hibernate-validator-6.1.5.Final.jar!/META-INF/services/javax.validation.spi.ValidationProvider文件内容是org.hibernate.validator.HibernateValidator

所以红框里的ServiceLoader<ValidationProvider> loader得到了一个ValidationProvider的实现(org.hibernate.validator.HibernateValidator)

再回去看javax.validation.Validation

3. 默认消息文件的位置

hibernate-validator-6.1.5.Final.jar!/org/hibernate/validator下面的ValidationMessages_xx.properties

4. annotation约束的实现类的位置

hibernate-validator-6.1.5.Final.jar!/org/hibernate/validator/internal/constraintvalidators/的bv和mv下面

5. annotation约束的实现类的绑定关系

绑定关系类是org.hibernate.validator.internal.metadata.core.ConstraintHelper

ConstraintHelper是在上面最后一个红框里ValidatorFactoryImpl的构造函数里被实例化的(ConstraintHelper constraintHelper = ConstraintHelper.forAllBuiltinConstraints();)

如何绑定关系的呢?在ConstraintHelper构造函数里调用了如下代码

putBuiltinConstraint( tmpConstraints, NotNull.class, NotNullValidator.class );

说明NotNull这个约束的验证器实现类是 NotNullValidator,在构造函数的最后把这些绑定函数都给了enabledBuiltinConstraints对象

当调用验证的时候   会通过会调用isBuiltinConstraint函数来判断是否该annotation约束是否是包里的还是自定义的。

并通过依次调用getAllValidatorDescriptors=>getDefaultValidatorDescriptors这2个函数从enabledBuiltinConstraints获取验证的实现类

6. 验证的实现类的获取

实现类是org.hibernate.validator.internal.engine.ValidatorImpl

通过调用hibernate-validator-6.1.5.Final.jar的ValidatorFactoryImpl的getValidator()获取的

 

7.控制校验顺序

通过@GroupSequence指定分组顺序

public class UserVo {    

    /**
     * 单体查询校验分组
     */
    @GroupSequence({Default.class, Extended.class})
    public interface QueryValidatorGroup {
        public interface Default {
        }
        public interface Extended {
        }
    }
    /**
     * 列表查询校验分组
     */
    @GroupSequence({Default1.class, Extended1.class})
    public interface ListValidatorGroup {
        public interface Default1 {
        }
        public interface Extended1 {
        }
    }

    @NotEmpty(groups={Default1.class})
    private String userId;
    
    @NotEmpty(groups={Extended.class, Extended1.class})
    private String userNo;

    @NotEmpty(groups={Default.class})
    private String userName;
    
    @NotEmpty(groups={Extended.class})
    private String userNickName;

    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserNickName() {
        return userNickName;
    }
    public void setUserNickName(String userNickName) {
        this.userNickName = userNickName;
    }
    public String getUserNo() {
        return userNo;
    }
    public void setUserNo(String userNo) {
        this.userNo = userNo;
    }
}

这里有2个分组,分别是QueryValidatorGroup和ListValidatorGroup,每组都要先验证带有Default 的字段,如果Default字段只要有一个验证失败的时候,就不去做带有Extended字段的验证了。

验证代码:

package com.example.demo;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorConfiguration;

import com.example.demo.UserVo.ListValidatorGroup;
import com.example.demo.UserVo.QueryValidatorGroup;

public class ValidatorTest {

    public static void main(String[] args) {
        // 验证单体查询校验分组 这里Default字段是userName,Extended字段是(userNo,userNickName)
        // 其中 userNo既是单体查询校验分组的Extended也是列表查询校验分组的Extended
        // 测试1 
        UserVo userVo = new UserVo();
        HibernateValidatorConfiguration configure = Validation.byProvider(HibernateValidator.class).configure();
        ValidatorFactory validatorFactory = configure.failFast(false).buildValidatorFactory();
        // 根据validatorFactory拿到一个Validator
        Validator validator = validatorFactory.getValidator();
        
        
        // 使用validator对结果进行校验
        Set<ConstraintViolation<UserVo>> result = validator.validate(userVo, QueryValidatorGroup.class);

        System.out.println("测试1");
        // 对结果进行遍历输出
        result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())
                .forEach(System.out::println);
        
       
        //  测试2
        System.out.println("测试2");
        UserVo userVo2 = new UserVo();
        userVo2.setUserName("a");
        configure = Validation.byProvider(HibernateValidator.class).configure();
         validatorFactory = configure.failFast(false).buildValidatorFactory();
        Set<ConstraintViolation<UserVo>> result2 = validator.validate(userVo2, QueryValidatorGroup.class);
        // 对结果进行遍历输出
        result2.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())
                .forEach(System.out::println);
        
        // 验证列表查询校验分组
        // 测试3
        System.out.println("测试3");
        UserVo userVo3 = new UserVo();
        configure = Validation.byProvider(HibernateValidator.class).configure();
         validatorFactory = configure.failFast(false).buildValidatorFactory();
        Set<ConstraintViolation<UserVo>> result3 = validator.validate(userVo3, ListValidatorGroup.class);
        // 对结果进行遍历输出
        result3.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())
                .forEach(System.out::println);
        
        // 测试4
        System.out.println("测试4");
        UserVo userVo4 = new UserVo();
        userVo4.setUserId("a");
        configure = Validation.byProvider(HibernateValidator.class).configure();
         validatorFactory = configure.failFast(false).buildValidatorFactory();
        Set<ConstraintViolation<UserVo>> result4 = validator.validate(userVo4, ListValidatorGroup.class);
        // 对结果进行遍历输出
        result4.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())
                .forEach(System.out::println);

    }

}

运行结果

测试1
userName 不能为空: null
测试2
userNickName 不能为空: null
userNo 不能为空: null
测试3
userId 不能为空: null
测试4
userNo 不能为空: null
l

UserVo也可以换个写法

package com.example.demo;

import javax.validation.GroupSequence;
import javax.validation.constraints.NotEmpty;



public class UserVo {    

    /**
     * 单体查询校验分组
     */
    @GroupSequence({QueryValidatorGroup.Default.class, QueryValidatorGroup.Extended.class})
    public interface QueryValidatorGroup {
        public interface Default {
        }
        public interface Extended {
        }
    }
    /**
     * 列表查询校验分组
     */

    @GroupSequence({ListValidatorGroup.Default.class, ListValidatorGroup.Extended.class})
    public interface ListValidatorGroup{
        public interface Default {
        }
        public interface Extended {
        }
    }

    @NotEmpty(groups={ListValidatorGroup.Default.class})
    private String userId;
    
    @NotEmpty(groups={QueryValidatorGroup.Extended.class, ListValidatorGroup.Extended.class}) 
    private String userNo;
    
    @NotEmpty(groups={QueryValidatorGroup.Default.class})
    private String userName;
    
    @NotEmpty(groups={QueryValidatorGroup.Extended.class}) 
    private String userNickName;
    
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserNickName() {
        return userNickName;
    }
    public void setUserNickName(String userNickName) {
        this.userNickName = userNickName;
    }
    public String getUserNo() {
        return userNo;
    }
    public void setUserNo(String userNo) {
        this.userNo = userNo;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值