Bean Validation 技术规范特性概述

概述 Bean Validation 规范

Bean 是 Java Bean 的缩写,在 Java 分层架构的实际应用中,从表示层到持久化层,每一层都需要对 Java Bean 进行业务符合性验证,如图 1 所示。然而对于同一个 Java Bean 的对象,在每一层都需要实现同样的验证逻辑时,这将是一项耗时且容易诱发错误的做法。Bean Validation 规范的目标就是避免多层验证的重复性。事实上,开发者更倾向于将验证规则直接放到 Java Bean 本身,使用注解的方式进行验证规则的设计。

图 1. Java 分层验证结构示意图


JSR303 规范(Bean Validation 规范)提供了对 Java EE 和 Java SE 中的 Java Bean 进行验证的方式。该规范主要使用注解的方式来实现对 Java Bean 的验证功能,并且这种方式会覆盖使用 XML 形式的验证描述符,从而使验证逻辑从业务代码中分离出来,如图 2 所示。

图 2. Java Bean 验证模型示意图



JSR303 规范提供的 API 是 Java Bean 对象模型的一般扩展,它并不局限于某一层或者某一编程模型,在服务器端和客户端都可使用,其最大的特点就是易用而且灵活。
Hibernate Validator 4.0 是 JSR303 规范的参考实现,本文所有示例代码均使用该参考实现。

下面给出一个 Bean Validation 的简单示例(清单 1):

清单 1:

public class Employee { 
 @NotNull(message = "The id of employee can not be null") 
 private Integer id; 

 @NotNull(message = "The name of employee can not be null") 
 @Size(min = 1,max = 10,message="The size of employee's name must between 1 and 10") 
 private String name; 

 public int getId() { 
 return id; 
 } 
 public void setId(int id) { 
 this.id = id; 
 } 
 public String getName() { 
 return name; 
 } 
 public void setName(String name) { 
 this.name = name; 
 } 
 public static void main(String[] args) { 
 Employee employee = new Employee(); 
 employee.setName("Zhang Guan Nan"); 
 ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); 
 Validator validator = vf.getValidator(); 
 Set<ConstraintViolation<Employee>> set = validator.validate(employee); 
 for (ConstraintViolation<Employee> constraintViolation : set) { 
 System.out.println(constraintViolation.getMessage()); 
 } 
 } 
 }

运行该示例的输出结果为:
The size of employee's name must between 1 and 10
The id of employee can not be null
从示例中可以看出,Bean Validation 使用注解(@NotNull 和 @Size)的方式对字段 id 和 name 进行了约束声明,当该 Java Bean 被实际使用时,相关的验证器就会对该类的实例进行验证确保其符合该约束声明。完成 Java Bean 的验证通常可分为如下四个步骤:
1、约束注解的定义
2、约束验证规则(约束验证器)
3、约束注解的声明
4、约束验证流程

本文第二大部分将详细介绍约束注解的定义和约束验证规则;第三大部分将详细介绍约束注解的声明和约束验证流程;第四大部分将介绍 JSR303 规范提供的 API。


约束的定义
约束注解

Bean Validation 规范对约束的定义包括两部分,一是约束注解,清单 1 中的 @NotNull 就是约束注解;二是约束验证器,每一个约束注解都存在对应的约束验证器,约束验证器用来验证具体的 Java Bean 是否满足该约束注解声明的条件。
在 Java Bean 中,对某一方法、字段、属性或其组合形式等进行约束的注解,即为约束注解,如清单 2 所示:

清单 2:

 @NotNull(message = "The id of employee can not be null") 
 private Integer id;

清单 2 的含义为:对于字段 id,在 Java Bean 的实例中值不能为空。对于每一个约束注解,在实际使用前必须有相关定义。JSR303 规范默认提供了几种约束注解的定义(见表 1),我们也可以扩展规范提供的 API,实现符合自身业务需求的约束注解。


表 1. Bean Validation 规范内嵌的约束注解定义

约束注解名称 约束注解说明
@Null 验证对象是否为空
@NotNull 验证对象是否为非空
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMin 验证 Number 和 String 对象是否大等于指定的值,小数存在精度
@DecimalMax 验证 Number 和 String 对象是否小等于指定的值,小数存在精度
@Size 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Digits 验证 Number 和 String 的构成是否合法
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
约束注解和普通的注解一样,一个典型的约束注解的定义应该至少包括如下内容(清单 3):

清单 3:

@Target({ })   // 约束注解应用的目标元素类型
 @Retention()   // 约束注解应用的时机
 @Constraint(validatedBy ={})  // 与约束注解关联的验证器
 public @interface ConstraintName{ 
 String message() default " ";   // 约束注解验证时的输出消息
 Class<?>[] groups() default { };  // 约束注解在验证时所属的组别
 Class<? extends Payload>[] payload() default { }; // 约束注解的有效负载
 }

约束注解应用的目标元素类型包括 METHOD, FIELD, TYPE, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER。METHOD 约束相关的 getter 方法;FIELD 约束相关的属性;TYPE 约束具体的 Java Bean;ANNOTATION_TYPE 用在组合约束中;该规范同样也支持对参数(PARAMETER)和构造器(CONSTRUCTOR)的约束。
验证时的组别属性将在本文第三大部分中组与组序列中详细介绍。
有效负载通常用来将一些元数据信息与该约束注解相关联,常用的一种情况是用负载表示验证结果的严重程度。
清单 4 给出一个验证字符串非空的约束注解的定义:

清单4:

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) 
 @Retention(RUNTIME) 
 @Documented 
 @Constraint(validatedBy = {NotEmptyValidator.class}) 
 public @interface NotEmpty { 
 String message() default "this string may be empty"; 
 Class<?>[] groups() default { }; 
 Class<? extends Payload>[] payload() default {}; 
 }

约束注解定义完成后,需要同时实现与该约束注解关联的验证器。约束验证器的实现需要扩展 JSR303 规范提供的接口 javax.validation.ConstraintValidator。清单 5 给出该接口。

清单 5:

public interface ConstraintValidator<A extends Annotation, T> { 
 void initialize(A constraintAnnotation); 
 boolean isValid(T value, ConstraintValidatorContext context); 
 }

该接口有两个方法,方法 initialize 对验证器进行实例化,它必须在验证器的实例在使用之前被调用,并保证正确初始化验证器,它的参数是约束注解;方法 isValid 是进行约束验证的主体方法,其中 value 参数代表需要验证的实例,context 参数代表约束执行的上下文环境。
对于清单 4 定义的约束注解,清单 6 给出了与该注解对应的验证器的实现。

清单 6:

public class NotEmptyValidator implements ConstraintValidator<NotEmpty, String>{ 
 public void initialize(NotEmpty parameters) { 
 } 
 public boolean isValid(String string, 
    ConstraintValidatorContext constraintValidatorContext) { 
 if (string == null) return false; 
 else if(string.length()<1) return false; 
 else return true; 
 } 
 }

至此,一个可以声明并使用的约束注解已经定义完毕,清单 7 将给出该约束注解在实际程序中的使用。为节省篇幅,这里只给出针对清单 1 的增加和修改内容,未给出全部的示例代码,您可以在本文的附录中获得全部的代码。

清单 7:

首先在清单 1 中的类 Employee 中加入字段 company 和相应的 getter 和 setter 方法:
 @NotEmpty 
 private String company; 
然后在 main 函数中加入如下代码清单:
 String company = new String(); 
 employee.setCompany(company); 
再次运行该程序,输出结果为:
 The id of employee can not be null 
 this string may be empty 
 The size of employee's name must between 1 and 10

约束的声明和验证流程

本文第二大部分介绍了如何定义约束注解和验证器,本章主要介绍如何在 Java Bean 中应用存在定义的约束注解,主要包括两部分:一是约束的声明;二是约束的验证流程。
在需要进行约束的目标元素前面用注解的方式即可声明约束,这意味着该目标元素必须满足该约束的验证条件。如清单 13 即在字段 id 上声明了约束 @NotNull:
清单 13:

@NotNull(message = "The id of employee can not be null") 
 private Integer id;

该目标元素在具体实例中被赋值后,Bean Validation 就会调用相关的流程进行验证。具体使用方式可以参见清单 14 所示,其中所涉及的接口将在本文第四大部分详细介绍。

清单 14:

ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); 
 Validator validator = vf.getValidator(); 
 Set<ConstraintViolation<Employee>> set = validator.validate(JavaBeanInstance); 
 for (ConstraintViolation<Employee> constraintViolation : set) { 
 System.out.println(constraintViolation.getMessage()); 
 }

Bean Validation 规范对 Java Bean 的验证流程如下:在实际使用中调用 Validator.validate(JavaBeanInstance) 方法后,Bean Validation 会查找在 JavaBeanInstance上所有的约束声明,对每一个约束调用对应的约束验证器进行验证,最后的结果由约束验证器的 isValid 方法产生,如果该方法返回 true,则约束验证成功,否则验证失败。验证失败的约束将产生约束违规对象(ConstraintViolation 的实例)并放到约束违规列表中。验证完成后所有的验证失败信息均能在该列表中查找并输出。
前提条件
Bean Validation 规范规定在对 Java Bean 进行约束验证前,目标元素必须满足以下条件:
如果验证的是属性(getter 方法),那么必须遵从 Java Bean 的命名习惯(JavaBeans 规范);
静态的字段和方法不能进行约束验证;
约束适用于接口和基类;
约束注解定义的目标元素可以是字段、属性或者类型等;
可以在类或者接口上使用约束验证,它将对该类或实现该接口的实例进行状态验证;
字段和属性均可以使用约束验证,但是不能将相同的约束重复声明在字段和相关属性(字段的 getter 方法)上。

转自:https://www.ibm.com/developerworks/cn/java/j-lo-beanvalid/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值