文章来源:http://blog.matrix.org.cn/kjj/entry/20070324
Tags: hibernatehibernate
2007-3-28 13:22:32 | 编辑
Hibernate Validation 中文
|
注释
|
用于
|
运行时检查
|
Hibernate Metadata 兼容
|
|
@Length(min=, max=)
|
property (字符串)
|
检查是字符串长度范围
|
列长度被设置到最大
|
|
@Max(value=)
|
property (数字,或代表数字的字符串)
|
检查值是否=或<max
|
在列上添加一个约束
|
|
@Min(value=)
|
property (数字,或代表数字的字符串)
|
检查值是否=或>min
|
在列上添加一个约束
|
|
@NotNull
|
property
|
是否null
|
列不为null
|
|
@NotEmpty
|
property
|
字符串不空或非NULl
链接不空或非null
|
对字符列非null约束
|
|
@Past
|
property (date 或 calendar)
|
检查是否日期在过去
|
在列上添加一个约束
|
|
@Future
|
property (date 或 calendar)
|
检查是否日期在将来
|
无
|
|
@Pattern(regex="regexp", flag=) or @Patterns( {@Pattern(...)} )
|
property (字符串)
|
检查是否属性匹配规则表达式给定的匹配标志 (see java.util.regex.Pattern )
|
无
|
|
@Range(min=, max=)
|
property (数字,或代表数字的字符串)
|
是否值min<=value<=max
|
在列上添加一个约束
|
|
@Size(min=, max=)
|
property (数组, 集合, map)
|
Min<=Size<=max
|
无
|
|
@AssertFalse
|
property
|
检查方法计算到false (多用在代码里检查约束)
|
无
|
|
@AssertTrue
|
property
|
检查方法计算到true (多用在代码里检查约束)
|
none
|
|
@Valid
|
property (对象)
|
在一个关联对象上递归的执行检验.如果对象是一个数组或者集合,对象将被递归的检验. 如果对象是一个map,元素将被递归的验证.
|
none
|
|
@Email
|
property (String)
|
检查是否字符创符合email规范
|
none
|
|
@CreditCardNumber
|
property (String)
|
字符串是否一个格式好的信誉卡号码(derivative of the Luhn algorithm)
|
none
|
|
@Digits
|
property (数字,或代表数字的字符串)
|
数字是否符合整数部分和小数部分的精度
|
定义列精度和范围
|
|
@EAN
|
property (字符串)
|
字符是否是格式化的 EAN 或者 UPC-A 编码
|
none
|
|
@Digits
|
property (numeric or string representation of a numeric)
|
check whether the property is a number having up to integerDigits integer digits and fractionalDigits fractonal digits
|
define column precision and scale
|
1.3.错误消息
随Hibernate 验证器一起的有一个被翻译成十种语言的默认错误消息(如果没有你所在地区的语言,请发送给我们一个补丁)你可以通过创建一个ValidatorMessages.properties( ValidatorMessages_loc.properties )文件覆盖这些消息,甚至当你在写你的验证器注释的时候你可以添加你自己的消息集合。如果hibernate验证器在你的资源文件里或者ValidatorMessage里不能找到一个key的对应值,那么他将返回默认的内建值。
作为选择,当你程序化在一个bean上检查验证规则或者你要一个完全不同的修改机制时你可以提供一个资源绑定,你可以提供一个org.hibernate.validator.MessageInterpolator接口的实现。
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用来描述约束违反强制性的默认字符串,你可以硬编码或者部分或者全部利用资源绑定机制。参数值将被注入消息里面当{parameter}字符串被找到(在我们的例子Capitalization is not {type} 将产生 Capitalization is not FIRST )把所有字符串都放在属性文件ValidatorMessages.properties是个好的实践.
@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>的类。
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自身。在单元测试里有一个小的例子。
如果你的约束可以在一些属性或者类型上被应用多次(用不同的参数)你可以用下面的注释形式
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Patterns {
Pattern[] value();
}
@Target(METHOD)
@Retention(RUNTIME)
@Documented
@ValidatorClass(PatternValidator.class)
public @interface Pattern {
String regexp();
}
基本上,注释以一个验证器注释数组的形式包含值属性
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;
}
}
然而这个例子仅仅演示了共用的属性验证,你也可以以可见的形式注释
@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类的Name属性将被检查null约束
第一章 使用验证框架
Hibernate验证器有意被用来实现多层数据验证,这些数据约束位于仅一个地方(被注释的域模型)并且在应用的不同层被检查。
这章我们将涵盖hibernate验证器在不同层的使用
2.1数据库模式级别验证
Out of the box ,hibernate验证器将把你为你的实体定义的约束传进映射元数据,例如,如果你实体的一个属性被注释为@NotNull 他的列将被声明为 not null 在由hibernate生成的 DDL 里。
使用 hbm2ddl,域模型约束将被在数据库中表示。
如果 ,因为某些原因,这些特征需要禁用,设置
hibernate.validator.apply_to_ddl 为 false
2.2 ORM 集成
Hibernate 验证器与hibernate和所有纯java的持久化提供者集成。
2.2.1基于hibernate事件的验证
Hibernate验证器已经内置两个hibernate事件监听器,任何时候一个PreInsertEvent 或者 PreUpdateEvent事件发生,监听器将确认这个实例的所
有约束并且在当任何约束被违反的时候抛出一个异常。一般地,对象将在由hibernate进行的插入和更新前被检查。这个将被级联的应用。这是激活验证流程最方便和容易的途径。在验证违反发生时,事件将抛出一个包含了用来描述每个失败消息的InvalidValues类型的数组的InvalidStateException类型的运行期异常。
如果hibernate 验证器被放在类路径里,Hibernate Annonations(或Hibernate EntityManager)将透明的使用他,如果由于某些原因需要禁用这个集成特征设置hibernate.validator.autoregister_listeners 为 false
注意:如果beans没有用验证注释注释,将不会有运行时性能消耗
在这种情况下你需要手工为hibernate设置事件监听器,下面是配置
<hibernate-configuration>
...
<event type="pre-update">
<listener
class="org.hibernate.validator.event.ValidateEventListener"/>
</event>
<event type="pre-insert">
<listener
class="org.hibernate.validator.event.ValidateEventListener"/>
</event>
</hibernate-configuration>
Hibernate 验证器与hibernate在基于事件的验证上没有关联,一个java持久化实体监听器是可用的。任何时候一个被监听的实体被持久化或者更新,hibernate验证器将确认所有此实体实例的约束并且在约束别违反的时候抛出异常,一般地,对象将在由java持久化提供者进行的插入和更新前被检查。这个将被级联的应用。在验证违反发生时,事件将抛出一个包含了用来描述每个失败消息的InvalidValues类型的数组的InvalidStateException类型的运行期异常。
如何使一个类可验证
@Entity
@EntityListeners( JPAValidateListener.class )
public class Submarine {
...
}
注意:与hibernate事件相比 java 持久化监听器有两个缺点。你需要为每个可验证的实体定义一个实体监听器。由你的提供者生成的DDL 将不会反射这些约束.
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);