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. POJ 2828-Buy Tickets(线段树)

    题意: 有n个人,每人有一定的价值,给n个安排,每次安排有两个数 p,v p是这个人前面人的个数 (直接插在第p个人后面其他人后移),v是它的价值,n个安排后 求最终的价值序列. 分析: 越在后面的安 ...

  2. 【Ubuntu Java 开发环境搭建 】

    配置环境变量  在终端下:  sudo gedit /etc/profile   这里当然有些熟悉ubuntu的朋友也可以用 vim,   刚从windows转过来的朋友还是用gedit看着舒服写. ...

  3. Tomcat 7 Connector 精读(1)

    这个类图是本人截取的最重要的类的方法和属性. 其中ProtocalHandler是协议处理器,tomcat支持的协议以下方法可以看到.不同协议实现了不同的ProtocalHandler类. publi ...

  4. python 网络编程(三)---TCP 服务器端客户端实现

    客户端 客户端主要有4个步骤: 1)创建一个socket以连接服务器. socket = socket.socket(family, type),family参数代表地址家族,可为AF_INET(包括 ...

  5. uva 11995 I Can Guess the Data Structure stack,queue,priority_queue

    题意:给你n个操做,判断是那种数据结构. #include<iostream> #include<cstdio> #include<cstdlib> #includ ...

  6. android NDK 实用学习(一)-获取java端类及其类变量

    近期为android 端项目包装一些c++代码,故学习ndk相关知识,现总结如下: 1,java与c++类型参照图: 2,此测试中使用的java类: package com.dasea.test.co ...

  7. Sitecore Digital Marketing System, Part 1: Creating personalized, custom content for site visitors(自定义SiteCore中的 Item的Personalize的Condition) -摘自网络

    Sitecore’s Digital Marketing System (DMS) can help you personalize the content your site displays to ...

  8. notepad 如何同时选中同一列的数据 Alt

    有时会经常遇到这种情况, 我们要选中数据中的某一列,这个在记事本中是实现不了的,不过我们可以用更高级一点的编辑器. 使用notepad可以帮助我们解决这个问题哦! 操作方法就是 按下ALT键 然后再去 ...

  9. A Tour of Go Exercise: Fibonacci closure

    Let's have some fun with functions. Implement a fibonacci function that returns a function (a closur ...

  10. ECSHOP在线手册之布局参考图-首页 index.dwt

        A.logo替换 1,设置方法 后台商店设置里,上传logo就行,注意logo的名称必须是logo.gif 2,代码相关 page_header.lbi 中 <a href=" ...