学习一款强大的运行期属性检查框架
题图:from Google
引子
用Annotations给类或者类的属性加上约束(constraint),在运行期检查属性值是很优雅的,Hibernate Validator是一个验证框架,不需要和Hibernate的其他部分绑定就可以使用。
Bean Validation
Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。缺省的元数据是 Java Annotations,通过使用 XML 可以对原有的元数据信息进行覆盖和扩展。在应用程序中,通过使用 Bean Validation 或是自己定义的约束(constraint),例如 @NotNull, @Max,就可以确保数据模型(JavaBean)的正确性。
Hibernate Validator
Hibernate Validator是Bean Validation的参考实现。Hibernate Validator提供了JSR 303规范中所有内置 constraint的实现,除此之外还有一些附加的constraint。
可以认为,Hibernate Validator是Bean Validation的一个具体实现,并且提供了更多的特性
1. 约束级别
- 字段级约束
- 属性级约束
- 类级别约束
- 约束的继承;约束会被子类继承,在校验子类时也会对父类进行校验
- 对象图; @Valid注解会对关联的对象也进行校验
注意:若同时对一个字段和属性加约束,该属性会被验证两次。
|
|
2. 校验约束
Validator接口提供三种方法校验实体对象或者对象中的属性
validate
12345Set<ConstraintViolation<User>> violations = validator.validate(user);Iterator it = violations.iterator();while(it.hasNext()) {System.out.println(it.next().getMessage());}validateProperty
12345Set<ConstraintViolation<User>> violations = validator.validateProperty(user, "username");Iterator it = violations.iterator();while(it.hasNext()) {System.out.println(it.next().getMessage());}validateValue
12345Set<ConstraintViolation<User>> violations = validator.validateValue(User.class, "username", null);Iterator it = violations.iterator();while(it.hasNext()) {System.out.println(it.next().getMessage());}
3. 校验组以及校验组序列
在使用约束时,可以定义其所属的校验组并定义其各组的校验顺序。hibernate validator可以通过注解形式和xml配置文件形式进行配置,出于去配置文件化的考虑,这里仅以注解形式的配置进行说明
校验组
如代码示例1中所示,注解中groups属性就是给约束注解进行分组,而后可以在调用validator.validate(user, "sexGroup")
时指定需要校验的组校验组序列
默认情况下,约束执行校验的顺序是不确定的。不过我们可以自定义其校验顺序。
需要注意的是:校验组序列中的校验组和这个校验组序列不能有循环引用,包括校验组继承,否则会抛出GroupDefinitionException
如下代码示例2所示
代码示例2
123456 //定义校验序列@GroupSequence({Default.class, "sexGroup", "usernameGroup"})public interface orderedChecks {}//使用指定校验序列来校验对象validator.validate(user, orderedChecks.class);
- 重定义默认校验组
- Bean Validation Annotation
在类上使用@GroupSequence注解,如下代码示例3中所示 - Hibernate Validator Annotation
在类上使用@GroupSequenceProvider注解,并自定义provider实现DefaultGroupSequenceProvider接口,详见附录hibernate validator文档2.3.2.2
代码示例3
1234567 //定义校验序列@GroupSequence({"sexGroup", "usernameGroup"})public class User {...}//使用指定校验序列来校验对象,其实就是使用sexGroup和usernameGroupvalidator.validate(user, Default.class);
4. 内置约束条件
- Bean Validate规定的约束条件
详见附录hibernate validator文档2.4.1 - Hibernate独有的约束条件
详见附录hibernate validator文档2.4.2
5. 多种方式创建validator实例
|
|
|
|
|
|
6. 自定义约束规则(不常用)
步骤如下,详见附录hibernate validator文档3.1
- 创建约束标注
- 实现一个验证器
- 定义默认的验证错误信息
7. XML配置文件(不提倡)
详见附录hibernate validator文档4.1
8. 通过Configuration自定义验证失败提示信息等特性(不常用)
由于默认Validator基本满足日常使用,因此对此内容简介,详见附录hibernate validator文档5.1
|
|
配置简单说明:
- messageInterpolator
验证失败提示信息解析 - traversableResolver
某些情况下, 我们可能不应该去获取一个属性的状态。比如延迟加载的属性或者与JPA中涉及到关联关系的时候。当验证这两种情况的属性的时候,很可能会触发一次对数据库的查询.可以通过TraversableResolver接口来控制能否访问某一个属性。
Hibernate Validator默认提供两种实现,其中DefaultTraversableResolver
对isReachable()和isTraversable()俩方法永远返回true。
可以自定义实现TraversableResolver接口,重写两种方法,然后通过configuration配置validator - constraintValidatorFactory
自定义约束校验器的工厂类
9. hibernate validator 独有的特性(区别于Bean Validation)
Hibernate Validator相对于Bean Validation有很多独有的特性,这里只说一下其中被Bean Validation列入包含计划的特性
- 方法约束:
使用相同的方式(如注解方式),可以对方法参数、返回值等信息进行校验。
为了可移植性,平时都尽可能只使用Bean Validation提供的特性,所以此特性只需了解即可,待Bean Validation纳入标准后再进行使用