java validator的原理与使用
http://developer.51cto.com/art/201104/253257_1.htm
ava EE 6核心特征:Bean Validation特性概述(2)

数据验证在 Java 分层结构的应用开发中占据着重要位置。Java EE 6 提出了 Bean Validation 规范,使用注解的方式对 Java Bean 进行约束验证,不局限于某一层次或者某一编程模型,灵活易用。本文将向您系统的介绍该规范的各种特性。
约束的定义
约束注解
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 { }; // 约束注解在验证时所属的组别
- Classextends 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 { };
- Classextends Payload>[] payload() default {};
- }
约束注解定义完成后,需要同时实现与该约束注解关联的验证器。约束验证器的实现需要扩展 JSR303 规范提供的接口 javax.validation.ConstraintValidator。清单 5 给出该接口。
清单 5:
- public interface ConstraintValidator<a < span="">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
多值约束
下面介绍 Bean Validation 规范的一个特性,多值约束(Multiple Constraints):对于同一个目标元素,在进行约束注解声明时可以同时使用不同的属性达到对该目标元素进行多值验证的目的。如清单 8 所示:
清单 8:
- public @interface ConstraintName{
- String message() default " ";
- Class[] groups() default { };
- Classextends Payload>[] payload() default { };
- @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
- @Retention(RUNTIME)
- @Documented
- @interface List {
- ConstraintName[] value();
- }
- }
实现多值约束只需要在定义约束注解的同时定义一个 List(@interface List{})。使用该约束注解时,Bean Validation 将 value 数组里面的每一个元素都处理为一个普通的约束注解,并对其进行验证,所有约束条件均符合时才会验证通过。
清单 9 定义了一个约束注解,它用来验证某一字符串是否包含指定的内容。
清单 9:
- @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
- @Retention(RUNTIME)
- @Documented
- @Constraint(validatedBy = PatternOfStringValidator.class)
- public @interface PatternOfString {
- String mustContainLetter();
- String message() default "this pattern may not be right";
- Class[] groups() default { };
- Classextends Payload>[] payload() default {};
- @Target({ METHOD, FIELD, ANNOTATION_TYPE})
- @Retention(RUNTIME)
- @interface List {
- PatternOfString[] value();
- }
- }
该约束注解对应的验证器如清单 10 所示:
清单 10:
- public class PatternOfStringValidator implements ConstraintValidator
- {
- private String letterIn;
- public void initialize(PatternOfString parameters) {
- this.letterIn=parameters.mustContainLetter();
- }
- public boolean isValid(String string,
- ConstraintValidatorContext constraintValidatorContext) {
- if (string.contains(letterIn))
- return true;
- return false;
- }
- }
如果想验证某一字符串是否同时包含两个子串,那么多值约束就显得比较重要了,清单 11 将详细给出多值约束的使用。
清单 11:
在清单 1 中的类 Employee 中增加如下字段 place 以及相应的 getter 和 setter 方法:
- @PatternOfString.List({
- @PatternOfString(mustContainLetter = "CH",
- message = "It does not belong to China"),
- @PatternOfString(mustContainLetter="MainLand",
- message="It does not belong to MainLand")})
- private String place;
然后在 main 函数中加入如下代码清单:
- String place = "C";
- employee.setPlace(place);
再次运行该程序,输出结果为:
- It does not belong to MainLand
- It does not belong to China
- this string may be empty
- The id of employee can not be null
- The size of employee's name must between 1 and 10
如果将 place 赋值为 String place = "CHINA",则输出结果为:
- this string may be empty
- The id of employee can not be null
- It does not belong to MainLand
- 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:
- @NotNull
- @Size(min = 1)
- @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
- @Retention(RUNTIME)
- @Documented
- @Constraint(validatedBy = {NotEmptyValidator2.class})
- public @interface NotEmpty2 {
- String message() default "this string may be empty";
- Class[] groups() default { };
- Classextends Payload>[] payload() default {};
- @Target({ METHOD, FIELD, ANNOTATION_TYPE})
- @Retention(RUNTIME)
- @interface List {
- NotEmpty2[] value();
- }
- }
java validator的原理与使用的更多相关文章
- 深入Java核心 Java内存分配原理精讲
深入Java核心 Java内存分配原理精讲 栈.堆.常量池虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同.本文将深入Java核心,详细讲解Java内存分配方面的知识. Java内存分 ...
- paip.java UrlRewrite 的原理and实现 htaccess正则表达式转换
paip.java UrlRewrite 的原理and实现 htaccess正则表达式转换 #---KEYWORD #-正则表达式 正则表达式 表示 非指定字符串开头的正则 排除指定目录.. 作者 老 ...
- Java虚拟机工作原理详解 (一)
一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了解java程序工作原理.首先,你写好java代码,保存到硬盘当中.然后你在命令行中输入 javac YourClassNam ...
- Java虚拟机工作原理详解
原文地址:http://blog.csdn.net/bingduanlbd/article/details/8363734 一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了 ...
- Java爬虫搜索原理实现
permike 原文 Java爬虫搜索原理实现 没事做,又研究了一下爬虫搜索,两三天时间总算是把原理闹的差不多了,基本实现了爬虫搜索的原理,本次实现还是俩程序,分别是按广度优先和深度优先完成的,广度优 ...
- Java虚拟机工作原理具体解释
一.类载入器 首先来看一下java程序的运行过程. 从这个框图非常easy大体上了解java程序工作原理.首先,你写好java代码,保存到硬盘其中.然后你在命令行中输入 javac YourClass ...
- Java基础知识强化之多线程笔记05:Java程序运行原理 和 JVM的启动是多线程的吗
1. Java程序运行原理: Java 命令会启动Java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程.该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 m ...
- Java validator整理
Java validator整理 因为想对方法的入参和出参作简单的非空或者非空字符做校验,所以找了下相关的@NotNull注解 类 | 说明 --- | --- javax.validation.co ...
- Java环境配置原理
Java环境配置原理详解 1.Jdk安装目录文件说明: 一般jdk安装目录及路径 \Java\jdk1.7.0_79\lib,里面主要包含以下文件夹. bin:主要存放的是java工具中常用命令如:j ...
随机推荐
- 非均匀B样条拟合MATLAB程序
直接上代码,多的不再说了. %------------------非均匀B样条拟合MATLAB程序----------------- clear k=; x=load('data.txt'); [n, ...
- HDU 5618 Jam's problem again CDQ分治 BC ROUND 70
题意:给你1e5个点(x,y,z),对于每一个点询问有多少个点(x1,y1,z1)满足x1<=x&&y1<=y&&z1<=z 分析:(官方题解奉上)很 ...
- ubuntu网站做图像外链
http://paste.ubuntu.org.cn
- JavaScript(class0526)
什么是JavaScript? HTML只是描述网页长相的标记语言,没有计算.判断能力,如果所有计算.判断(比如判断文本框是否为空.判断两次密码是否输入一致)都放到服务器端执行的话网页的话页面会非常慢. ...
- Storm因机器断电等,启动supervisor异常
Storm因机器断电等,启动supervisor错误 因机器断电或其他异常导致的supervisor意外终止,再次启动时报错: 2014-08-13 10:36:03 b.s.event [ERROR ...
- 挑战树莓派:谁才是Geek最爱的开发板?
树莓派(Raspberry Pi)是一块跟信用卡差不多大小的开发板,它的初衷是以低廉的硬件和开源软件扶持一些落后地区的电脑科学教育.由于它在性能和价格方面有一个很好的平衡点,所以很多硬件玩家也想买一个 ...
- 让IE浏览器支持CSS3圆角的方法
如果要想在IE浏览器中实现圆角的效果,我们一般都会采用圆角图片的方式.用图片的话,基本就跟浏览器没有多大关系了,因为任何浏览器都支持这种方式.今天我们主要是讲解如果用CSS3样式表来实现圆角效果,值得 ...
- ListView inside a ScrollView
ScrollView里面放ListView, ListView无法展开的解决方法 http://stackoverflow.com/questions/18367522/android-list-vi ...
- linux大于2T的磁盘使用GPT分区方式
MBR(Master Boot Record)(主引导记录)和GPT(GUID Partition Table)(GUID意为全局唯一标识符)是在磁盘上存储分区信息的两种不同方式 对于传统的MBR分区 ...
- [OC Foundation框架 - 7] NSArray的创建与遍历
NSArray是不可变的,不能先创建再添加元素 NSArray可以放入任何OC对象,但不能放入基本数据类型.结构体.枚举等非OC对象 不能存储nil A.常用方法1 创建 返回用量 是否含有某元素 ...