数据校验是任何一个应用程序都会用到的功能,无论是显示层还是持久层. 通常,相同的校验逻辑会分散在各个层中, 这样,不仅浪费了时间还会导致错误的发生(译注: 重复代码). 为了避免重复, 开发人员经常会把这些校验逻辑直接写在领域模型里面, 但是这样又把领域模型代码和校验代码混杂在了一起, 而这些校验逻辑更应该是描述领域模型的元数据.
Jsr303
JSR 303 - Bean Validation - 为实体验证定义了元数据模型和API. 默认的元数据模型是通过Annotations来描述的,但是也可以使用XML来重载或者扩展. Bean Validation API 并不局限于应用程序的某一层或者哪种编程模型
Hibernate Validator是参照jsr实现的。
第一个是示例
首先导入 validation-api.jar和 jboss-logging包
创建一个model类(UserModel)
UserModel中有三个约束:①用户名不能为空 ②密码长度位8~12 ③年龄大于等于18
import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size;
public class UserModel { @NotNull private Stringusername;
@NotNull @Size(min=8, max=12) private Stringpassword;
@Min(18) private int age; //省略getter, setter方法 } |
@NotNull, @Size, @Min 就是所属的约束性标注 |
测试类
public class ValidationTest { private static Validator validator;
@BeforeClass public static void setUp() { //创建工厂获取验证器 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); validator = factory.getValidator(); } @Test public void testValidationUserModel() { UserModel user = new UserModel(null,"12345678", 4); Set<ConstraintViolation<UserModel>> constraintViolations = validator.validate(user); Iterator<ConstraintViolation<UserModel>> ite = constraintViolations.iterator(); while(ite.hasNext()) { System.out.println(ite.next().getMessage()); } } } |
测试结果:
不能为null
最小不能小于18
在setUp方法中,我们通过ValidatorFactory得到了一个Validator的实例,Validator是线程安全的, 并且可以重复利用
Validate方法会返回一个set的ConstraintViolation
的实例的集合, 我们可以通过遍历它来查看有哪些验证错误. 前面三个测试用例显示了一些预期的校验约束
在testValidationUserModel中, 用户名为空, 并且年龄也小于18
如果一个对象没有校验出问题的话, 那么validate会返回一个空的set对象
定义约束
Beanvalidation的约束是通过java注解来标注的, 并且分为三种不同的注解类型
一.字段级 ( field level)约束
当约束被定义在字段上的时候, 这个字段的值是通过字段访问策略来获取并验证的. 也就是说Bean Validation的实现者会直接访问这个实例变量而不会调用属性的访问器(getter) 即使这个方法存在.
Tip:这个字段的访问级别( private, protected 或者 public) 对此没有影响
Tip:静态字段或者属性是不会被校验的
二.属性级别约束
和字段级别约束的区别是它的约束是定义在属性级别上的
并且只能定义在getter上面, 不能定义在setter上
三.类级别约束
最后, 一个约束也能够被放在类级别上. 当一个约束被标注在一个类上的时候,这个类的实例对象被传递给ConstraintValidator. 当需要同时校验多个属性来验证一个对象或者一个属性在验证的时候需要另外的属性的信息的时候, 类级别的约束会很有用.
约束继承
如果要验证的对象继承某个父类或者实现了某个接口, 那么定义在父类或者接口中的约束会在验证这个对象的时候被自动加载。
对象图
BeanValidation Api不仅能够用来校验单个实例对象,还能够用来校验完整的对象图
要使用这个功能,只需要在一个有关联关系的字段或者属性上标注@Valid. 这样,如果一个对象被校验,那么它的所有的标注了@Valid的关联对象都会被校验.
关联校验也适用于集合类型的字段
如果标注了@Valid, 那么当主对象被校验的时候, 这些集合对象中的元素也会被校验
Tip:对象图校验的时候会忽略null, 所以一般需要加上@NotNull和@Valid