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. [Bhatia.Matrix Analysis.Solutions to Exercises and Problems]ExI.3.7

    For every matrix $A$, the matrix $$\bex \sex{\ba{cc} I&A\\ 0&I \ea} \eex$$ is invertible and ...

  2. java jvm学习笔记一

    欢迎装载请说明出处:http://blog.csdn.net/yfqnihao java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式 ...

  3. [娱乐]GameMaker绘制参数方程的图像

    今天,我翻了旧物,硬着头皮看了这源码.突然恍然大悟,这岂不就是当年学的参数方程! 目前,最早开始教授参数方程实在高三时,并作为一门选修课程,简化了求解圆锥曲线方程的难度,在高考中也很容易拿分,考试过后 ...

  4. linux 学习之 rpm

    目前最常见的两种软件安装方式: 1.dpkg 2.rpm 1.dpkg 最早是由Debian Linux社群开发出来的,通过dpkg,Debian提供的软件就可以简单的安装,同时还能提供安装后的软件信 ...

  5. HW5.26

    public class Solution { public static void main(String[] args) { int totalCount = 0; int lineCount = ...

  6. C++ STL@ list 应用 (leetcode: Rotate Array)

    STL中的list就是一双向链表,可高效地进行插入删除元素. List 是 C++标准程式库 中的一个 类 ,可以简单视之为双向 连结串行 ,以线性列的方式管理物件集合.list 的特色是在集合的任何 ...

  7. leptonica 学习笔记2——pixBackgroundNormSimple

    1 pixBackgroundNormSimple 函数功能:自适应背影标准化 位置:adampmap.c /*-------------------------------------------- ...

  8. hdu 5505 GT and numbers

    GT and numbers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  9. hdoj 1234 开门人和关门人

    开门人和关门人 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) #include ...

  10. 通过dbcc page来查看表中的数据

    --1.先建表 CREATE TABLE test(idd INT NOT NULL,name VARCHAR(10) NULL) INSERT INTO TEST SELECT 1,'abcdefg ...