用Annotations 给类或者类的属性加上约束(constraint)在运行期检查属性值是很优雅的Hibernate Validator就是这样的一个框架该框架是十分容易的(就像参考文档中宣称的那样)几乎没有什么学习曲线Validator 是一个验证框架 不需要和Hibernate的其他部分绑定就可以使用只要在你的项目中添加Hibernateannotationsjar库就可以了那么下面就让我们看看怎么使用吧
Personjava 类
/*
* Created on Personjava
* @author
*/
package testannotationvalidator;
import orghibernatevalidatorLength;
import orghibernatevalidatorMin;
import orghibernatevalidatorValid;
//@Serializability//测试自定义约束
public class Person {
private String name;
private int age;
private Address address;
public Person() {}
@Valid //注意此处
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
thisaddress = address;
}
@Min(value = )
public int getAge() {
return age;
}
public void setAge(int age) {
thisage = age;
}
@Length(min = )
public String getName() {
return name;
}
public void setName(String name) {
thisname = name;
}
}
Addressjava 类
/*
* Created on Addressjava
* @author
*/
package testannotationvalidator;
import orghibernatevalidatorLength;
import orghibernatevalidatorMax;
import orghibernatevalidatorMin;
public class Address {
private String street;
private int num;
public Address() {}
@Min(value = )
@Max(value = )
public int getNum() {
return num;
}
public void setNum(int num) {
thisnum = num;
}
@Length(min = max = )
public String getStreet() {
return street;
}
public void setStreet(String street) {
thisstreet = street;
}
}
上面是两个用 Validator Annotations 注释的 类 每个属性都用 约束限制了下面看看测试的类吧:
TestValidatorjava 类
/*
* Created on
* @author icerain
*/
package testannotationvalidator;
import orghibernatevalidatorClassValidator;
import orghibernatevalidatorInvalidValue;
public class TestValidator {
public void test() {
Address add = new Address();
addsetNum();
addsetStreet();
Person p = new Person();
psetAddress(add);
psetAge();
psetName(ice);
/******************Test validator ********/
// 注意该处只验证了Person 为了说明 @Valid 注释的使用
ClassValidator<Person> classValidator = new ClassValidator<Person> (Personclass);
InvalidValue[] validMessages = classValidatorgetInvalidValues(p);
for (InvalidValue value : validMessages) {
Systemoutprintln(InvalidValue 的长度是: + validMessageslength
+ 验证消息是: + valuegetMessage()
+ PropertyPath 是: + valuegetPropertyPath()
+ \n\t PropertyName 是: +valuegetPropertyName()
+ Value 是: + valuegetValue()
+ Bean 是: + valuegetBean()
+\n\t BeanClass 是: + valuegetBeanClass());
}
}
public static void main(String[] args) {
new TestValidator()test();
}
}
程序的输出如下
InvalidValue 的长度是: 验证消息是: 必须大于等于 PropertyPath 是:age
PropertyName 是: age Value 是: Bean 是: testannotationvalidatorPerson@ddb
BeanClass 是:class testannotationvalidatorPerson
InvalidValue 的长度是: 验证消息是: 长度必须介于 与 之间 PropertyPath 是:name
PropertyName 是: name Value 是: ice Bean 是: testannotationvalidatorPerson@ddb
BeanClass 是:class testannotationvalidatorPerson
InvalidValue 的长度是: 验证消息是: 必须大于等于 PropertyPath 是:addressnum
PropertyName 是: num Value 是: Bean 是: testannotationvalidatorAddress@d
BeanClass 是:class testannotationvalidatorAddress
InvalidValue 的长度是: 验证消息是: 长度必须介于 与 之间 PropertyPath 是:addressstreet
PropertyName 是: street Value 是: Bean 是: testannotationvalidatorAddress@d
BeanClass 是:class testannotationvalidatorAddress
可以看出不满足约束的值都被指出了
同时该句: ClassValidator<Person> classValidator = new ClassValidator<Person> (Personclass);
我们只验证了 Person 在Person里面的Address的属性 由于有@Valid Annotations 所以 Address的相关属性也被机联验证了
如果 把@Valid Annotations 去掉结果如下:
InvalidValue 的长度是: 验证消息是: 必须大于等于 PropertyPath 是:age
PropertyName 是: age Value 是: Bean 是: testannotationvalidatorPerson@fefd
BeanClass 是:class testannotationvalidatorPerson
InvalidValue 的长度是: 验证消息是: 长度必须介于 与 之间 PropertyPath 是:name
PropertyName 是: name Value 是: ice Bean 是: testannotationvalidatorPerson@fefd
BeanClass 是:class testannotationvalidatorPerson
可以看出 没有验证 Address
当然了 你还可以只验证一个属性 没有必要验证整个类只需要在调用classValidatorgetInvalidValues(page)方法时 加上你要验证的属性就可以了如我们只想验证age 属性 把代码改为如下所示:
InvalidValue[] validMessages = classValidatorgetInvalidValues(page); //只验证age 属性
运行结果如下:
InvalidValue 的长度是: 验证消息是: 必须大于等于 PropertyPath 是:age
PropertyName 是: age Value 是: Bean 是: testannotationvalidatorPerson@cb
BeanClass 是:class testannotationvalidatorPerson
只是验证了 age 属性
怎么样 很简单吧 关于 Hibernate Validator 内建的验证Annotations 大家可以看看 API 或者 参考文档(中文版我正在翻译中 请访问我的 Blog 获得最新信息)
如果你要写自己的约束呢 你不用担心 这也是很容易的 任何约束有两部分组成: [约束描述符 即注释]the constraint descriptor (the annotation) 和[约束validator 即 实现类] the constraint validator (the implementation class)下面我们扩展Hibernate Test suit 中的一个Test 来讲解一下
首先: 要声明一个constraint descriptor 如下:
package testannotationvalidator;
import javalangannotationDocumented;
import static javalangannotationElementTypeTYPE;
import static javalangannotationElementTypeFIELD;
import static javalangannotationElementTypeMETHOD;
import javalangannotationRetention;
import static javalangannotationRetentionPolicyRUNTIME;
import javalangannotationTarget;
import orghibernatevalidatorValidatorClass;
/**
* Dummy sample of a beanlevel validation annotation
*
* @author Emmanuel Bernard
*/
@ValidatorClass(SerializabilityValidatorclass)
@Target({METHODFIELDTYPE})
@Retention(RUNTIME)
@Documented
public @interface Serializability {
int num() default ;
String message() default bean must be serialiable;
}
@ValidatorClass(SerializabilityValidatorclass) 指出了 constraint validator 类
@Target({METHODFIELDTYPE})
@Retention(RUNTIME)
@Documented
这几个我就不用解释了吧
Serializability 里面声明了一个 message 显示约束的提示信息 num 只是为了说明一个方面 在这里面没有实际用途用
然后就是 实现一个constraint validator 类 该类要实现Validator<ConstraintAnnotation>这里是SerializabilityValidatorjava 如下:
//$Id: SerializabilityValidatorjavav // :: epbernard Exp $
package testannotationvalidator;
import javaioSerializable;
import orghibernatevalidatorValidator;
/**
* Sample of a beanlevel validator
*
* @author Emmanuel Bernard
*/
public class SerializabilityValidator implements Validator<Serializability> Serializable {
public boolean isValid(Object value) {
//这里只是Validator 里面的 实现验证规则的 方法 value 是要验证的值
Systemoutprintln(IN SerializabilityValidator isValid:+valuegetClass()+: +valuetoString());
return value instanceof Serializable;
}
public void initialize(Serializability parameters) {
// 在这里可以 取得 constraint descriptor 里面的属性 如上面我们声明的 num
Systemoutprintln(IN SerializabilityValidator: parameters:+ parametersnum() );
}
}
然后在你的类中应用@Serializability就可以约束一个类实现Serializable 接口了 如下:
在我们的Personjava类 添加@SerializabilityAnnotations 把Personjava 中的 //@Serializability //测试自定义约束 注释去掉就ok了
运行结果如下:
InvalidValue 的长度是: 验证消息是: bean must be serialiable PropertyPath 是:null
PropertyName 是: null Value 是: testannotationvalidatorPerson@adc Bean 是: testannotationvalidatorPerson@adc
BeanClass 是:class testannotationvalidatorPerson
现在把Person类实现 javaioSerializable 接口 则没有出现 验证错误消息
消息的国际化也是很简单的把Serializability中的message 改为以{}扩住的 属性文件的Key就可以了
public @interface Serializability {
int num() default ;
String message() default {Serializable}; //bean must be serialiable; //消息的国际化
}
然后编辑资料文件 注意 该资源文件中要包括 Hibernate Validator 内建的资源 可以在该org\hibernate\validator\resources 包里面的资源文件基础上修改 在打包里面 这样就可以了 自己打包可能不太方便你可以把该包里面的文件复制出来然后放到你自己的项目包下在自己编辑 该测试中 我是放在 test\resources 包下的
然后在 资源文件中添加 Serializable = 这么一行 样例如下:
#DefaultValidatorMessagesproperties (DefaultValidatorMessages_zhproperties 不再列出^_^)
#下面是 Hibernate Validator 内建的国际化消息
validatorassertFalse=assertion failed
validatorassertTrue=assertion failed
validatorfuture=must be a future date
validatorlength=length must be between {min} and {max}
validatormax=must be less than or equal to {value}
validatormin=must be greater than or equal to {value}
validatornotNull=may not be null
validatorpast=must be a past date
validatorpattern=must match {regex}
validatorrange=must be between {min} and {max}
validatorsize=size must be between {min} and {max}
#下面是自定义的消息
Serializable=Bean not Serializable//加上自己定义的国际化消息
在构造ClassValidator 时要添上 资源文件 如下:(在测试类中)
ClassValidator<Person> classValidator = new ClassValidator<Person> (PersonclassResourceBundlegetBundle(testresourcesDefaultValidatorMessages));//加载资源
这样就可以了 当然 你还可以 更改 Hibernate Validator 的消息(不是在上面的资源文件中直接修改validatorlength = 等等 ) 还记得 Validator 注释中有个 message 元素吗? 你以前用的都是默认值现在你可以该为你自己定义的了如:validatorlength 我把他改为 该字符串的长度不符合规定范围范围 在资源文件中添加一行键值属性对(key定义为 myMsg)如下:
myMsg=该字符串的长度不符合规定范围范围
并且还要在@Length 注释中提供message的引用的key 如下@Length(min = message = {myMsg})
再一次运行测试 我们就可以看到上面两条自定义绑定的消息了 如下:
InvalidValue 的长度是: 验证消息是: Bean 不是 可 Serializable PropertyPath 是:null
PropertyName 是: null Value 是: testannotationvalidatorPerson@bd Bean 是: testannotationvalidatorPerson@bd
BeanClass 是:class testannotationvalidatorPerson
InvalidValue 的长度是: 验证消息是: 该字符串的长度不符合规定范围范围 PropertyPath 是:name
PropertyName 是: name Value 是: ice Bean 是: testannotationvalidatorPerson@bd
BeanClass 是:class testannotationvalidatorPerson
怎么样比你想象的简单吧
上面我们讨论了 Hibernate Validator 的主要用法: 但是 该框架有什么用呢?
看到这里其实不用我在多说了 大家都知道怎么用什么时候用 作为一篇介绍性文章我还是在此给出一个最常用的例子吧更好的使用方式大家慢慢挖掘吧
比如 : 你现在在开发一个人力资源(HR)系统 (其实是我们ERP课程的一个作业 ^_^) 里面要处理大量的数据尤其是在输入各种资料时 如 登记员工信息 如果你公司的员工的年龄要求是 那么你所输入的年龄就不能超出这个范围 你可能会说这很容易啊 不用Validator就可以解决啊这保持数据前验证就可以啦 如if ( egetAge() > || egetAge() < ) 给出错误信息 然后提示重新输入不就OK啦 用得着 兴师动众的来个第三方框架吗?
是啊 当就验证这一个属性时 没有必要啊 ! 但是一个真正的HR 系统会只有一个属性要验证吗? 恐怕要有N多吧
你要是每一个都那样 写一段验证代码 是不是很烦啊 况且也不方便代码重用 现在考虑一些 Validator 是不是更高效啊拦截到 约束违例的 属性 就可以直接得到 国际化的消息 可以把该消息显示到一个弹出对话框上 提示更正!