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 ...
随机推荐
- MySQL中间层 Atlas
Atlas是由 Qihoo 360, Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bu ...
- mycat分布式mysql中间件(数据库切分概述)[转]
mysql数据库切分 前言 通 过MySQLReplication功能所实现的扩展总是会受到数据库大小的限制,一旦数据库过于庞大,尤其是当写入过于频繁,很难由一台主机支撑的时 候,我们还是会面临到扩展 ...
- uvalive 4670 Dominating Patterns
在文本串中找出现次数最多的子串. 思路:AC自动机模板+修改一下print函数. #include<stdio.h> #include<math.h> #include< ...
- dateline 在数据库中就是 整型字段。date函数是可以转换成可读日期的。
返回数据中的dateline全部用date()函数转换后再返回,是要嵌套循环还是遍历,代码怎么写? //查询我的活动 function user_activity_info_by_uid($uid){ ...
- 关于图像读取函数imread()的一点使用经验,注意默认参数的赋值
读入数字图像到数组,用CNN进行训练,发现关于图像读取的一个问题. 问题描述:读取灰度数字图像,在验证时发现存在错误,从图像到数组中的值不完全一样? main code as follows: int ...
- Java Collections Framework
集合OR 容器 通常我们会用数组去保存一些基本数据类型,数组是编译器支持的类型,但是数组的一个明显缺点就是具有固定尺寸,而在一般情况下,只有在程序运行的时候,我们才能知道要保存的具体数目. Java类 ...
- Java SAX Parser
SAX is an abbreviation and means "Simple API for XML". A Java SAX XML parser is a stream o ...
- Keil µVision4 中出现中文乱码的解决办法
首先得说一下,以前都没有遇到过类似的问题,但是看到有个同学曾经满篇的乱码那叫个心疼. 这里我所说的办法其实只是格式转换的问题,对于其他原因造成的,可能会在以后遇到的时候再来处理了.另外,在将代码文件转 ...
- [iOS基础控件 - 6.6.1] 展示团购数据代码
1.主控制器: // // ViewController.m // GroupPurchase // // Created by hellovoidworld on 14/12/3. // Cop ...
- [html][转]常用返回顶部代码
转至:http://jingyan.baidu.com/article/7082dc1ca6b928e40a89bd1a.html 一.使用HTML的锚标记最简单了 但是唯一的缺点就是样式不怎么样,会 ...