http://developer.51cto.com/art/201104/253257_1.htm

ava EE 6核心特征:Bean Validation特性概述(2)

2011-04-02 14:33 张冠楠 陈志娴 IBM developerWorks 字号:T | T

数据验证在 Java 分层结构的应用开发中占据着重要位置。Java EE 6 提出了 Bean Validation 规范,使用注解的方式对 Java Bean 进行约束验证,不局限于某一层次或者某一编程模型,灵活易用。本文将向您系统的介绍该规范的各种特性。

AD:WOT2015 互联网运维与开发者大会 热销抢票

约束的定义

约束注解

Bean Validation 规范对约束的定义包括两部分,一是约束注解,清单 1 中的 @NotNull 就是约束注解;二是约束验证器,每一个约束注解都存在对应的约束验证器,约束验证器用来验证具体的 Java Bean 是否满足该约束注解声明的条件。

在 Java Bean 中,对某一方法、字段、属性或其组合形式等进行约束的注解,即为约束注解,如清单 2 所示:

清单 2:

  1. @NotNull(message = "The id of employee can not be null")
  2. 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:

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

约束注解应用的目标元素类型包括 METHOD, FIELD, TYPE, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER。METHOD 约束相关的 getter 方法;FIELD 约束相关的属性;TYPE 约束具体的 Java Bean;ANNOTATION_TYPE 用在组合约束中;该规范同样也支持对参数(PARAMETER)和构造器(CONSTRUCTOR)的约束。

验证时的组别属性将在本文第三大部分中组与组序列中详细介绍。

有效负载通常用来将一些元数据信息与该约束注解相关联,常用的一种情况是用负载表示验证结果的严重程度。

清单 4 给出一个验证字符串非空的约束注解的定义:

清单 4:

  1. @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
  2. @Retention(RUNTIME)
  3. @Documented
  4. @Constraint(validatedBy = {NotEmptyValidator.class})
  5. public @interface NotEmpty {
  6. String message() default "this string may be empty";
  7. Class[] groups() default { };
  8. Classextends Payload>[] payload() default {};
  9. }

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

清单 5:

  1. public interface ConstraintValidator<a < span="">extends Annotation, T> {
  2. void initialize(A constraintAnnotation);
  3. boolean isValid(T value, ConstraintValidatorContext context);
  4. }

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

对于清单 4 定义的约束注解,清单 6 给出了与该注解对应的验证器的实现。

清单 6:

  1. public class NotEmptyValidator implements ConstraintValidator<notempty, string>{
  2. public void initialize(NotEmpty parameters) {
  3. }
  4. public boolean isValid(String string,
  5. ConstraintValidatorContext constraintValidatorContext) {
  6. if (string == null) return false;
  7. else if(string.length()<1) return false;
  8. else return true;
  9. }
  10. }

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

清单 7:

首先在清单 1 中的类 Employee 中加入字段 company 和相应的 getter 和 setter 方法:

  1. @NotEmpty
  2. private String company;

然后在 main 函数中加入如下代码清单:

  1. String company = new String();
  2. employee.setCompany(company);

再次运行该程序,输出结果为:

  1. The id of employee can not be null
  2. this string may be empty
  3. The size of employee's name must between 1 and 10

 多值约束

下面介绍 Bean Validation 规范的一个特性,多值约束(Multiple Constraints):对于同一个目标元素,在进行约束注解声明时可以同时使用不同的属性达到对该目标元素进行多值验证的目的。如清单 8 所示:

清单 8:

  1. public @interface ConstraintName{
  2. String message() default " ";
  3. Class[] groups() default { };
  4. Classextends Payload>[] payload() default { };
  5. @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
  6. @Retention(RUNTIME)
  7. @Documented
  8. @interface List {
  9. ConstraintName[] value();
  10. }
  11. }

实现多值约束只需要在定义约束注解的同时定义一个 List(@interface List{})。使用该约束注解时,Bean Validation 将 value 数组里面的每一个元素都处理为一个普通的约束注解,并对其进行验证,所有约束条件均符合时才会验证通过。

清单 9 定义了一个约束注解,它用来验证某一字符串是否包含指定的内容。

清单 9:

  1. @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
  2. @Retention(RUNTIME)
  3. @Documented
  4. @Constraint(validatedBy = PatternOfStringValidator.class)
  5. public @interface PatternOfString {
  6. String mustContainLetter();
  7. String message() default "this pattern may not be right";
  8. Class[] groups() default { };
  9. Classextends Payload>[] payload() default {};
  10. @Target({ METHOD, FIELD, ANNOTATION_TYPE})
  11. @Retention(RUNTIME)
  12. @interface List {
  13. PatternOfString[] value();
  14. }
  15. }

该约束注解对应的验证器如清单 10 所示:

 清单 10:

  1. public class PatternOfStringValidator implements ConstraintValidator
  2. {
  3. private String letterIn;
  4. public void initialize(PatternOfString parameters) {
  5. this.letterIn=parameters.mustContainLetter();
  6. }
  7. public boolean isValid(String string,
  8. ConstraintValidatorContext constraintValidatorContext) {
  9. if (string.contains(letterIn))
  10. return true;
  11. return false;
  12. }
  13. }

如果想验证某一字符串是否同时包含两个子串,那么多值约束就显得比较重要了,清单 11 将详细给出多值约束的使用。

清单 11:

在清单 1 中的类 Employee 中增加如下字段 place 以及相应的 getter 和 setter 方法:

  1. @PatternOfString.List({
  2. @PatternOfString(mustContainLetter = "CH",
  3. message = "It does not belong to China"),
  4. @PatternOfString(mustContainLetter="MainLand",
  5. message="It does not belong to MainLand")})
  6. private String place;

然后在 main 函数中加入如下代码清单:

  1. String place = "C";
  2. employee.setPlace(place);

再次运行该程序,输出结果为:

  1. It does not belong to MainLand
  2. It does not belong to China
  3. this string may be empty
  4. The id of employee can not be null
  5. The size of employee's name must between 1 and 10

如果将 place 赋值为 String place = "CHINA",则输出结果为:

  1. this string may be empty
  2. The id of employee can not be null
  3. It does not belong to MainLand
  4. The size of employee's name must between 1 and 10

可见,该约束会对声明的两个约束注解分别进行验证,只要存在不符合约束验证规则的 Java Bean 实例,就将产生相应的验证失败信息。约束注解声明的时候可以根据不同的约束值使用 message 参数给出不同的输出信息。

组合约束

下面介绍 Bean Validation 规范中另一个重要的特性:组合约束。Bean Validation 规范允许将不同的约束进行组合来创建级别较高且功能较多的约束,从而避免原子级别约束的重复使用。如清单 4 定义的约束注解 @NotEmpty,是用来判断一个字符串在非空的基础上长度至少为 1,其实际意义等同于 @NotNull 和 @Size(min=1)的组合形式,因此可以将 @NotEmpty 约束定义为组合约束 NotEmpty2,如清单 12 所示:

清单 12:

  1. @NotNull
  2. @Size(min = 1)
  3. @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
  4. @Retention(RUNTIME)
  5. @Documented
  6. @Constraint(validatedBy = {NotEmptyValidator2.class})
  7. public @interface NotEmpty2 {
  8. String message() default "this string may be empty";
  9. Class[] groups() default { };
  10. Classextends Payload>[] payload() default {};
  11. @Target({ METHOD, FIELD, ANNOTATION_TYPE})
  12. @Retention(RUNTIME)
  13. @interface List {
  14. NotEmpty2[] value();
  15. }
  16. }

java validator的原理与使用的更多相关文章

  1. 深入Java核心 Java内存分配原理精讲

    深入Java核心 Java内存分配原理精讲 栈.堆.常量池虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同.本文将深入Java核心,详细讲解Java内存分配方面的知识. Java内存分 ...

  2. paip.java UrlRewrite 的原理and实现 htaccess正则表达式转换

    paip.java UrlRewrite 的原理and实现 htaccess正则表达式转换 #---KEYWORD #-正则表达式 正则表达式 表示 非指定字符串开头的正则 排除指定目录.. 作者 老 ...

  3. Java虚拟机工作原理详解 (一)

    一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了解java程序工作原理.首先,你写好java代码,保存到硬盘当中.然后你在命令行中输入 javac YourClassNam ...

  4. Java虚拟机工作原理详解

    原文地址:http://blog.csdn.net/bingduanlbd/article/details/8363734 一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了 ...

  5. Java爬虫搜索原理实现

    permike 原文 Java爬虫搜索原理实现 没事做,又研究了一下爬虫搜索,两三天时间总算是把原理闹的差不多了,基本实现了爬虫搜索的原理,本次实现还是俩程序,分别是按广度优先和深度优先完成的,广度优 ...

  6. Java虚拟机工作原理具体解释

    一.类载入器 首先来看一下java程序的运行过程. 从这个框图非常easy大体上了解java程序工作原理.首先,你写好java代码,保存到硬盘其中.然后你在命令行中输入 javac YourClass ...

  7. Java基础知识强化之多线程笔记05:Java程序运行原理 和 JVM的启动是多线程的吗

    1. Java程序运行原理:     Java 命令会启动Java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程.该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 m ...

  8. Java validator整理

    Java validator整理 因为想对方法的入参和出参作简单的非空或者非空字符做校验,所以找了下相关的@NotNull注解 类 | 说明 --- | --- javax.validation.co ...

  9. Java环境配置原理

    Java环境配置原理详解 1.Jdk安装目录文件说明: 一般jdk安装目录及路径 \Java\jdk1.7.0_79\lib,里面主要包含以下文件夹. bin:主要存放的是java工具中常用命令如:j ...

随机推荐

  1. 4种activity的启动模式

    在android里,有4种activity的启动模式,分别为: “standard” (默认) “singleTop” “singleTask” “singleInstance” 它们主要有如下不同: ...

  2. selenium+testNG+Ant

    好几天没写了,抽时间写下,也好有个总结: 1.selenium+testNG+Ant (1)ant 是构建工具 他的作用就是运行你配置好的东西 而tentng.xml你可以认为他是管理test的一个配 ...

  3. 单元测试工具之Xunit

    在.NET开发中的单元测试工具之——xUnit.Net  原始出处 http://zhoufoxcn.blog.51cto.com/792419/1172320 在上一篇<在.NET开发中的单元 ...

  4. google学术反向代理及IPV6免流量上网【教育网BUPT】

    google反向代理 google https://awk.so/ 学术反向代理 https://awk.so/scholar/?hl=zh-CN 2015年1.1号开始流量计费,2元/G 无VPS用 ...

  5. mac usb转串口 连接树莓PI

    USB 转串口是淘宝买的 http://item.taobao.com/item.htm?spm=a1z09.2.9.50.YOJBwG&id=38963495468&_u=4m1dr ...

  6. opencv 在工业中的应用:模板匹配

    模板匹配在工业中经常有两个用途,一模板匹配进行产品定位,二根据匹配度来判断是OK的产品还是NG的产品.我用OPENCV做了个模板匹配定位的DEMO. (1)点击打开图像按钮打开一幅图像 (2)点击定义 ...

  7. PDF/WORD/EXCEL 图片预览

    一.PDF/WORD/EXCEL 转 XPS 转 第一页内容 转 图片 WORD.EXCEL转XPS (Office2010) public bool WordToXPS(string sourceP ...

  8. POJ 2986 A Triangle and a Circle 圆与三角形的公共面积

    计算几何模板 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h& ...

  9. stm32 时钟配置——外部时钟倍频、内部时钟倍频 【worldsing笔记】

    stm32可选的时钟源 在STM32中,可以用内部时钟,也可以用外部时钟,在要求进度高的应用场合最好用外部晶体震荡器,内部时钟存在一定的精度误差. 准确的来说有4个时钟源可以选分别是HSI.LSI.H ...

  10. 第1组UI组件:布局管理器

    1 布局管理的来源 为了让UI在不同的手机屏幕上都能运行良好----不同手机屏幕的分辨率/尺寸并不完全相同,如果让程序手动控制每个组件的大小.位置,会给编程带来巨大的麻烦.为了解决这个问题.andro ...