Hibernate验证器
第 4 章 Hibernate验证器
注解是一种为领域模型(domain model)指定不变约束的简洁而幽雅的方法。例如,你能 表示一个属性永远不为null,一个帐户余额一定是正值,等等。这些域模型约束通过为bean中的属性添加 注解来加以声明。随后一个验证器(validator)会读取并检查这些约束。验证机制可以执行于应用程序中的 不同层(表现层、数据访问层),而不必复述任何(前述)这些规则。Hibernate验证器正为这一目的而设计的。
Hibernate验证器工作在两个层次上。第一层,它能检查内存中一个类的实例是否违反约束。 第二层,它能将约束应用于Hibernate元模型上,并将它们融入生成的数据库schema中。
每个约束注解(constraint annotation)和一个验证器实现关联,该验证器负责检查位于实体实例上的约束。 一个验证器也能(可选地)将约束应用于Hibernate元模型上,让Hibernate生成表示这一约束的DDL。使用合适的事件监听器,你能 让Hibernate在插入和更新时执行检查操作。Hibernate验证器并不局限于同Hibernate一起使用。 你能在你应用程序的任何地方方便地使用它。
在运行时检查实例时,Hibernate验证器返回违反约束的信息, 这些信息以一个InvalidValue数组的形式返回。 除了众多其他信息外,InvalidValue包含了一个错误描述消 息,该信息可以内嵌与注解相捆绑的参数值(例如长度限制),以及能被提取至ResourceBundle的消息字串。
4.1. 约束
4.1.1. 什么是约束?
约束通过注解表示。一个约束通常有一些用来参数化约束限制的属性。约束应用于带注解的元素。
4.1.2. 内建约束
Hibernate验证器有些内建约束,这些约束覆盖了大多数的基本数据检查。随后我们会看到, 你不必受制于这些内置约束,因为一分钟内就可以写出你自己的约束。
表 4.1. 内建约束
注解 | 应用目标 | 运行时检查 | Hibernate元数据影响 |
---|---|---|---|
@Length(min=, max=) | 属性(String) | 检查字符串长度是否符合范围 | 列长度会被设到最大值 |
@Max(value=) | 属性 (以numeric或者string类型来表示一个数字) | 检查值是否小于或等于最大值 | 对列增加一个检查约束 |
@Min(value=) | 属性(以numeric或者string类型来表示一个数字) | 检查值是否大于或等于最小值 | 对列增加一个检查约束 |
@NotNull | 属性 | 检查值是否非空(not null) | 列不为空 |
@Past | 属性(date或calendar) | 检查日期是否是过去时 | 对列增加一个检查约束 |
@Future | 属性 (date 或 calendar) | 检查日期是否是将来时 | 无 |
@Pattern(regex="regexp", flag=) | 属性 (string) | 检查属性是否与给定匹配标志的正则表达式相匹配(见 java.util.regex.Pattern ) | 无 |
@Range(min=, max=) | 属性(以numeric或者string类型来表示一个数字) | 检查值是否在最小和最大值之间(包括临界值) | 对列增加一个检查约束 |
@Size(min=, max=) | 属性 (array, collection, map) | 检查元素大小是否在最小和最大值之间(包括临界值) | 无 |
@AssertFalse | 属性 | 检查方法的演算结果是否为false(对以代码方式而不是注解表示的约束很有用) | 无 |
@AssertTrue | 属性 | 检查方法的演算结果是否为true(对以代码方式而不是注解表示的约束很有用) | 无 |
@Valid | 属性 (object) | 对关联对象递归的进行验证。如果对象是集合或数组,就递归地验证其元素。如果对象是Map,则递归验证其值元素。 | 无 |
属性(String) | 检查字符串是否符合有效的email地址规范。 | 无 |
4.1.3. 错误信息
Hibernate验证器提供了一组默认的错误提示信息,它们被翻译成多种语言(如果你的语言不在其中,请给 我们寄一个补丁)。你可以在org.hibernate.validator.resources.DefaultValidatorMessages.properties 之外创建ValidatorMessages.properties或ValidatorMessages_loc.properties 文件并改变相应的键值,籍此覆盖那些(默认)信息。你甚至可以在写自己的验证器 注解时添加你自己的附加消息集。
或者你可以以编程方式检查bean的验证规则并提供相应的ResourceBundle。
4.1.4. 编写你自己的约束
扩展内建约束集是极其方便的。任何约束都包括两部分:约束描述符(注解) 和约束验证器(实现类)。下面是一个简单的用户定义描述符:
@ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Capitalized {
CapitalizeType type() default Capitalize.FIRST;
String message() default "has incorrect capitalization";
}
type参数描述属性应该如何被大写。这是一个完全依赖于注解业务(逻辑)的用户 参数。
message是用于描述约束违规的默认字符串,它是强制要求的。你可以采取硬编码的方式, 或者通过Java ResourceBundle机制将message的部分/全部内容提取至外部文件。一旦发现message中{parameter}字符串, 就会在{parameter}这个位置注入相应的参数值(在我们的例子里Capitalization is not {type}会生成 Capitalization is not FIRST), 可以将message对应的整个字符串提取至外部文件ValidatorMessages.properties,这也是一种良好实践。 见Error messages。
@ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Capitalized {
CapitalizeType type() default Capitalize.FIRST;
String message() default "{validator.capitalized}";
} ...
#in ValidatorMessages.properties
validator.capitalized=Capitalization is not {type}
如你所见{}符号是递归的。
为了将一个描述符连接到它的验证器实现,我们使用@ValidatorClass 元注解。验证器类参数必须指定一个实现了Validator<ConstraintAnnotation> 的类。
我们现在要实现验证器(也就是实现规则检查)。一个验证器实现能检查一个属性的值 (实现PropertyConstraint),并且/或者可以修改hibernate映射元数据 (实现PersistentClassConstraint),籍此表示数据库级的约束。
public class CapitalizedValidator
implements Validator<Capitalized>, PropertyConstraint {
private CapitalizeType type; //part of the Validator<Annotation> contract,
//allows to get and use the annotation values
public void initialize(Capitalized parameters) {
type = parameters.type();
} //part of the property constraint contract
public boolean isValid(Object value) {
if (value==null) return true;
if ( !(value instanceof String) ) return false;
String string = (String) value;
if (type == CapitalizeType.ALL) {
return string.equals( string.toUpperCase() );
}
else {
String first = string.substring(0,1);
return first.equals( first.toUpperCase();
}
}
}
如果违反约束,isValid()方法将返回false。更多例子请参考内建验证器实现。
至此我们只看到属性级的验证,你还可以写一个Bean级别的验证注解。Bean自身会被传递给验证器, 而不是bean的属性实例。只要对bean自身进行注解即可激活验证检查。在单元测试套件中还可以找到一个小例子。
4.1.5. 注解你的领域模型
既然你现在已经熟悉注解了,那么对语法也应该很清楚了。
public class Address {
private String line1;
private String line2;
private String zip;
private String state;
private String country;
private long id; // a not null string of 20 characters maximum
@Length(max=20)
@NotNull
public String getCountry() {
return country;
} // a non null string
@NotNull
public String getLine1() {
return line1;
} //no constraint
public String getLine2() {
return line2;
} // a not null string of 3 characters maximum
@Length(max=3) @NotNull
public String getState() {
return state;
} // a not null numeric string of 5 characters maximum
// if the string is longer, the message will
//be searched in the resource bundle at key 'long'
@Length(max=5, message="{long}")
@Pattern(regex="[0-9]+")
@NotNull
public String getZip() {
return zip;
} // should always be true
@AssertTrue
public boolean isValid() {
return true;
} // a numeric between 1 and 2000
@Id @Min(1)
@Range(max=2000)
public long getId() {
return id;
}
}
上面的例子只展示了公共属性验证,你还可以对任何可见度的字段(field)进行注解。
@MyBeanConstraint(max=45)
public class Dog {
@AssertTrue private boolean isMale;
@NotNull protected String getName() { ... };
...
}
你可以对接口进行注解。Hibernate验证器会检查给定bean所扩展或实现的所有父类和接口, 籍以读取相应的验证器注解(信息)。
public interface Named {
@NotNull String getName();
...
} public class Dog implements Named { @AssertTrue private boolean isMale; public String getName() { ... }; }
在验证Dog bean时会检查name属性的有效性(不为null)。
4.2. 使用验证器框架
Hibernate验证器旨在实现多层数据验证,我们在一处表示约束(带注解的域模型),然后将其运用于 应用程序的不同层。
4.2.1. 数据库schema层次验证
无须额外手续,Hibernate Annotations会自动将你为实体定义的约束翻译为映射元数据。例如,如果你的实体 的一个属性注解为@NotNull,在Hibernate生成的DDL schema中这列会被定义为 not null。
4.2.2. Hibernate基于事件的验证
Hibernate验证器有两个内建Hibernate事件监听器。当一个PreInsertEvent 或PreUpdateEvent发生时,监听器会验证该实体实例的所有约束,如有违反会抛出一个异常。 基本上,在Hibernate执行任何插入和更新前对象会被检查。这是激活验证过程的最便捷最简单的方法。当遇到约束 违规时,事件会引发一个运行时InvalidStateException,该异常包含一个描述每个错误的 InvalidValue数组。
<hibernate-configuration>
...
<event type="pre-update">
<listener
class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/>
</event>
<event type="pre-insert">
<listener
class="org.hibernate.validator.event.ValidatePreInsertEventListener"/>
</event>
</hibernate-configuration>
注意
在使用Hibernate Entity Manager时,Validation框架会被自动激活。如果bean不带验证注解, 就不会有性能损失。
4.2.3. 程序级验证
Hibernate验证器能应用于你应用程序代码中的任何地方。
ClassValidator personValidator = new ClassValidator( Person.class );
ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) ); InvalidValue[] validationMessages = addressValidator.getInvalidValues(address);
头两行为执行类检查而准备Hibernate验证器。第一行依赖于嵌入在Hibernate验证器内的错误 消息(见Error messages),第二行为这些消息准备资源包。这些代码只执行一次, 并将验证器进行缓存处理,这种方式是一种良好实践。
第三行真正验证了Address实例并返回一个InvalidValue数组。 你的应用程序逻辑随后可以对错误做出响应。
除了针对整个bean你还可以
https://docs.jboss.org/hibernate/annotations/3.4/reference/zh_cn/html/validator.html
Hibernate验证器的更多相关文章
- spring mvc: Hibernate验证器(字段不能为空,在1-150自己)
spring mvc: Hibernate验证器(字段不能为空,在1-150自己) 准备: 下载Hibernate Validator库 - Hibernate Validator.解压缩hibern ...
- Spring MVC Hibernate验证器
下面的示例演示如何使用Spring Web MVC框架在表单中使用错误处理和验证器. 首先使用Eclipse IDE,并按照以下步骤使用Spring Web Framework开发基于动态表单的Web ...
- Spring MVC-集成(Integration)-Hibernate验证器示例(转载实践)
以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_hibernate_validator.htm 说明:示例基于Spring MVC ...
- Converter(转换器)与Formatter(格式化) ,Validator(验证器)
Converter(转换器)与Formatter(格式化)都可以用于将一种对象类型转换为另一种对象类型.Converter是通用元件,可以在应用程序的任意层中使用,而Fotermatter这是专门为W ...
- Spring MVC -- 验证器
输入验证是Spring处理的最重要Web开发任务之一.在Spring MVC中,有两种方式可以验证输入,即利用Spring自带的验证框架,或者利用JSR 303实现.本篇博客将介绍这两种输入验证方法. ...
- springMVC中使用 JSR-303验证器( Validation 接口 )
在pom.xml,添加validator验证器的依赖 <dependency> <groupId>org.hibernate</groupId> <artif ...
- 9、 Struts2验证(声明式验证、自定义验证器)
1. 什么是Struts2 验证器 一个健壮的 web 应用程序必须确保用户输入是合法.有效的. Struts2 的输入验证 基于 XWork Validation Framework 的声明式验证: ...
- linux上使用google身份验证器(简版)
系统:centos6.6 下载google身份验证包google-authenticator-master(其实只是一个.zip文件,在windwos下解压,然后传进linux) #cd /data/ ...
- vue-validator(vue验证器)
官方文档:http://vuejs.github.io/vue-validator/zh-cn/index.html github项目地址:https://github.com/vuejs/vue-v ...
随机推荐
- Working with bounded Task Flows
Working with Bounded Task Flows, Regions and Routers in JDeveloper 11g Purpose In this tutorial, y ...
- PS 图像调整算法——阈值
PS里面这个算法,先将图像转成灰度图像,然后根据给定的阈值,大于该阈值的像素赋值为1,小于该阈值的赋值为0. if x>T, x=1; if x<T, x=0; 原图: 效果图:阈值为 1 ...
- OpenCV分通道显示图片,灰度,融合,直方图,彩色直方图
代码有参考跟整合:没有一一列出出处 // split_rgb.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <io ...
- H5页面转成图片并下载到本地
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- iframe局部刷新的二种实现方法
需求描述: 当页面有一部分是不变的或整个页面的图片很多时,可以考虑使用局部刷新,以提高整体的下载速度与用户体验. 1,iframe实现局部刷新的方法一 复制代码代码示例: <script t ...
- J2SE-程序执行与内存图
全局程序运行内存图 基础数据类型:byte,short,int,long(整数) float,double(浮点) -- 数值 char ...
- 工作中EF遇到的问题
EF的条件中,无法用转格式,时间差作为条件,这时在EF6中,可以用 DbFunctions 这个类,例如: db.NewsComments.Any( (entity.PostDate - p.Pos ...
- IT小团队的管理者的突围之道
笔者前几天被问到一个问题,你在团队管理方面有什么值得分享的吗?咋一听,实用千言万语,但是事后回忆说出来的东西感觉空无一物,缺少干货.故想通过写一篇随笔思考整理一下,刷新一下自己对小团队管理的认知.这里 ...
- python结巴(jieba)分词
python结巴(jieba)分词 一.特点 1.支持三种分词模式: (1)精确模式:试图将句子最精确的切开,适合文本分析. (2)全模式:把句子中所有可以成词的词语都扫描出来,速度非常快,但是不能解 ...
- day11_jsp/EL/JSTL学习笔记
一.jsp概述 JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP实际上就是Servlet. JSP这门技术的最大 ...