诸神的博客
诸神
我的首页
文章
相册
圈子
留言
管理
 
    当前所在页面:首页>>文章>>Hbiernate Validator使用简介
Hbiernate Validator使用简介
    作者:stef_wu 来源: 发表时间:2008-01-11

 
 

Hibernate Validator是基于Hibernate Core的一套Annotation的验证框架。可以和Hibernate 的GenerDdl结合使用,来生成数据表时添加规则,也可以通过代码的形式完成对象属性的有效性验证,并且抛出验证中产生的错误,使用简单。下面详细介绍:
首先,下载Hibernate Validator:
http://nchc.dl.sourceforge.net/sourceforge/hibernate/hibernate-validator-3.0.0.GA.zip
然后开始Hibernate Validator之旅。
1,最基本的验证:
直接开始一个最简单的验证测试:
首先准备一个待验证的对象:User:

public class User {
@NotEmpty
 @Length(min = 2, max = 6)
 private String userName;
 @NotNull
 @Range(min = 1, max = 120)
 private Integer age;
 @Valid
 private Address address;
 @NotNull
 @Email
 private String email;
 @Pattern(regex = "\\d{3}-\\d{3}-\\d{6,9}")
private String number;

//Getter&&setter

验证标签可以放在属性之上,也可以放在Getter方法之上,比如:

@Length(min = 2, max = 6)
public String getUserName(){
return this.userName;
}


注意User对象中还有一个复合对象Address,我们使用@ Valid标签标记,表示在验证User对象的时候,自动的也去验证Address对象,并把验证信息统一返回。
下面是Address对象:

public class Address {
 @Pattern(regex = "\\d{6}")
 private String zip;
 @NotEmpty
 private String name;
 public final String getZip() {
  return zip;
 }
 public final void setZip(String zip) {
  this.zip = zip;
 }
 public final String getName() {
  return name;
 }
 public final void setName(String name) {
  this.name = name;
 }
}

然后我们来写一个简单的测试,对User进行验证:

可以看到,在测试用例中的所有User属性都是错误的,关于各个标签的详细含义和使用,将在下面讲解。我们运行该测试,测试通过,控制台输出:

信息: Hibernate Annotations 3.2.1.GA
=========================
长度必须介于 2 与 6 之间
class com.thtf.ezone.ezframework.validator.User:userName
wwwwwww
=========================
必须介于 1 与 120 之间
class com.thtf.ezone.ezframework.validator.User:age
-1
=========================
not a well-formed email address
class com.thtf.ezone.ezframework.validator.User:email
www.com
=========================
必须符合 "\d{3}-\d{3}-\d{6,9}"
class com.thtf.ezone.ezframework.validator.User:number
222-222-33
=========================
必须符合 "\d{6}"
class com.thtf.ezone.ezframework.validator.Address:zip
wwwwwww
=========================
may not be null or empty
class com.thtf.ezone.ezframework.validator.Address:name

=========================
不能为空白
class com.thtf.ezone.ezframework.validator.User:userName
   
=========================
buenng wei kongbai haha
class com.thtf.ezone.ezframework.validator.User:userName
   
=========================
buenng wei kongbai haha
class com.thtf.ezone.ezframework.validator.User:userName

依次输出了所有的错误信息,包括Address里面的验证错误都统一输出。Hibernate Validator使用InvalidValue对象来包装一个验证的错误,使用ClassValidator来作为验证处理器。关于这两个对象的方法请参见API Doc。

下表列出了Hibernate Validator提供的内置的验证器:

Annotation 施加于 检查项 Hibernate生成相关表字段
@Length(min=, max=) 属性(String类型) 检查String长度是否在范围之内 字段的长度会被设置为最大长度所定义的值
@Max(value=) 属性(数字,或者内容为数字的String) 检查值是否小于等于Max值 在该字段上添加一个check约束
@Min(value=) 属性(数字,或者内容为数字的String) 检查值是否大于等于Max值 在该字段上添加一个check约束
@NotNull 属性 属性不能为null 字段设置为 not null
@NotEmpty 属性 属性不能为null且不能为空(比如String就不能为"")如果是集合类型的话,不能为null且不能为空(size()==0) 字段设置为 not null(String的话)
@Past 属性(Date或者calendar) 检查时间为过去时间 在该字段上添加一个check约束
@Future 属性(Date或者calendar) 检查时间为将来时间
@Pattern(regex="regexp"
, flag=) or @Patterns(
{@Pattern(...)} )
属性(String类型) 检查属性根据匹配标识(flag)来判断是否要求匹配(java.util.regex.Pattern)
@Range(min=, max=) 属性(数字,或者内容为数字的String) 检查属性值是否在范围之内,包括相等的情况 在该字段上添加一个check约束
@Size(min=, max=) 属性(array,collection,map) 检查元素个数是否在范围之内,包括相等的情况
@AssertFalse 属性 检查返回值为false
@AssertTrue 属性 检查返回值为true
@Valid 属性(Object) 级联的检查关联的对象。如果对象是一个Collection或者数组,则检查其中的每一个对象。如果对象是Map,则检查每一个Value域对象。
@Email 属性(String) 检查属性是否符合Email规则  
@Digits 属性(数字,或者内容为数字的String) 检查值是否是一个数字  

 

创建自己的验证规则
要在Hibernate Validator里面创建一个自定义的验证规则是很简单的。下面就来创建一个类似于JWeb里面@Validator(name="string",value="blank;trim",required")的验证器NotBlank。
首先创建一个NotBlank标签:

@ValidatorClass(NotBlankValidator.class)
@Target( { java.lang.annotation.ElementType.METHOD,
		java.lang.annotation.ElementType.FIELD })
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Documented
public @interface NotBlank {
	String message() default "{validator.notBlank}";
}

注意这里要使用@ValidatorClass来指明该标签使用哪个验证器来完成具体的验证。标签会有一个Message属性,用来表示错误的信息提示。这里使用的是ResourceBundle来从资源文件里面读取。关于错误消息的自定义,将在下面讲解。
然后来创建具体的验证器:

public class NotBlankValidator implements Validator<NotBlank>,
		PropertyConstraint, Serializable {
	private static final long serialVersionUID = 3873258797919992347L;
	public boolean isValid(Object value) {
		if (value == null)
			return false;
		if (value instanceof String) {
			return ((String) value).trim().length() > 0;
		}
		return false;
	}
	@SuppressWarnings("unchecked")
	public void apply(Property property) {
		if (!(property.getPersistentClass() instanceof SingleTableSubclass)
				&& !(property.getValue() instanceof Collection)) {
			// single table should not be forced to null
			if (!property.isComposite()) {
				Iterator<Column> iter = (Iterator<Column>) property
						.getColumnIterator();
				while (iter.hasNext()) {
					iter.next().setNullable(false);
				}
			}
		}
	}
	public void initialize(NotBlank parameters) {

	}
}

 

 

首先,一般的验证器只需要实现Validator接口即可。如果需要验证器对Hibernate生成数据库表有影响的话,需要实现PropertyConstraint接口。
public boolean isValid(Object value)是Validator里面定义的方法,用来做具体的验证。public void apply(Property property)是PropertyConstraint接口里定义的方法,用来对Hibernate生成表的时候做一定的规则。该验证器在验证时只处理String类型比较,并且能在相应的表的字段上完成添加not null规则。最后public void initialize(NotBlank parameters)是Validator接口定义的,可以在这里面通过parameters.getXXX()来得到在Annotation里面定义的其他属性值。
下面来测试这个自定义的验证标签。首先修改User对象

public class User {
	@NotBlank
	@Length(min = 2, max = 6)
	private String userName;

 

这里使用了@NotBlank来标记userName属性。

public void testSelfValidator() {
		ClassValidator cv = new ClassValidator(User.class);
		User user = new User();
		Address address = new Address();
		address.setName("address1");
		address.setZip("610019");
		user.setAddress(address);
		user.setAge(20);
		user.setEmail("wwww@www.com");
		user.setNumber("222-222-3333333");
		user.setUserName("    ");
		InvalidValue[] vms = cv.getInvalidValues(user);
		for (InvalidValue iv : vms) {
			System.out.println("=========================");
			System.out.println(iv.getMessage());
			System.out.println(iv.getBean().getClass() + ":"
					+ iv.getPropertyName());
			System.out.println(iv.getValue());
		}
		assertEquals(1, vms.length);
	}

 

接下来的测试,注意user.setUserName("    ")这行,他符合@@Length(min = 2, max = 6)的规则,但不符合@NotBlank的规则,执行该测试,控制台中输出:

不能为空白
class com.thtf.ezone.ezframework.validator.User:userName
'    '
=========================
验证成功。

错误消息自定义
Hibernate Validator中的错误消息都是放在ValidatorMessages.properties文件里面的,也可以通过覆盖该文件里面的消息达到自定义错误消息的目的:
下面列出所有的Hibernate内建消息:
validator.assertFalse=assertion failed
validator.assertTrue=assertion failed
validator.future=must be a future date
validator.length=length must be between {min} and {max}
validator.max=must be less than or equal to {value}
validator.min=must be greater than or equal to {value}
validator.notNull=may not be null
validator.past=must be a past date
validator.pattern=must match "{regex}"
validator.range=must be between {min} and {max}
validator.size=size must be between {min} and {max}

刚才我们在建立NotBlank标签的时候使用了一个Message来作为默认的提示,这里,我们来看看这个是怎么完成的。

public @interface NotBlank {
	String message() default "{validator.notBlank}";
}

 

首先在classpath下面创建一个ValidatorMessages.properties文件,
在其中添加一项:validator.notBlank=不能为空白,
通过转码得到:
validator.notBlank=\u4e0d\u80fd\u4e3a\u7a7a\u767d
OK,就这么简单。

也可以在使用标签是定义自定义的错误信息,
比如:修改User对象:

@NotBlank(message = "用户名不能为空")
	@Length(min = 2, max = 6)
	private String userName;

 

然后测试:

public void testSelfValidator() {
		ClassValidator cv = new ClassValidator(User.class);
		User user = new User();
		Address address = new Address();
		address.setName("address1");
		address.setZip("610019");
		user.setAddress(address);
		user.setAge(20);
		user.setEmail("wwww@www.com");
		user.setNumber("222-222-3333333");
		user.setUserName("    ");
		InvalidValue[] vms = cv.getInvalidValues(user);
		for (InvalidValue iv : vms) {
			System.out.println("=========================");
			System.out.println(iv.getMessage());
			System.out.println(iv.getBean().getClass() + ":"
					+ iv.getPropertyName());
			System.out.println(iv.getValue());
		}
		assertEquals(1, vms.length);
	}

 

控制台输出结果为:
信息: Hibernate Annotations 3.2.1.GA
=========================
用户名不能为空
class com.thtf.ezone.ezframework.validator.User:userName

同样,在这里我们也可以通过资源文件来达到国际化的目的:
创建资源文件:vmessages_zh.properties
在其中添加一行:
validator.notBlank=buenng wei kongbai haha
然后修改User对象:

@NotBlank(message = "{validator.notBlank}")
	@Length(min = 2, max = 6)
	private String userName;

 

完成测试:

public void testSelfValidator() {
	ClassValidator cv = new ClassValidator(User.class, ResourceBundle.getBundle("vmessages"));
	User user = new User();
		Address address = new Address();
		address.setName("address1");
		address.setZip("610019");
		user.setAddress(address);
		user.setAge(20);
		user.setEmail("wwww@www.com");
		user.setNumber("222-222-3333333");
		user.setUserName("    ");
		InvalidValue[] vms = cv.getInvalidValues(user);
		for (InvalidValue iv : vms) {
			System.out.println("=========================");
			System.out.println(iv.getMessage());
			System.out.println(iv.getBean().getClass() + ":"
					+ iv.getPropertyName());
			System.out.println(iv.getValue());
		}
		assertEquals(1, vms.length);
	}

 

 

控制台输出:
=========================
buenng wei kongbai haha
class com.thtf.ezone.ezframework.validator.User:userName
'    '
注意这里的new ClassValidator(User.class, ResourceBundle.getBundle("vmessages"));完成了绑定国际化资源文件的动作。

验证一个对象中的某一个属性:
Hibernate Validator可以只测试一个对象中的某一个属性:下面是一个测试用例:

public void testObjectOneProperty() {
		ClassValidator cv = new ClassValidator(User.class, ResourceBundle
				.getBundle("vmessages"));
		User user = new User();
		Address address = new Address();
		address.setName("address1");
		address.setZip("610019");
		user.setAddress(address);
		user.setAge(20);
		user.setEmail("wwww@www.com");
		user.setNumber("222-222-3");
		user.setUserName("    ");
		InvalidValue[] vms = cv.getInvalidValues(user, "userName");
		assertEquals(1, vms.length);
		for (InvalidValue iv : vms) {
			System.out.println("=========================");
			System.out.println(iv.getMessage());
			System.out.println(iv.getBean().getClass() + ":"
					+ iv.getPropertyName());
			System.out.println(iv.getValue());
		}
		assertEquals("buenng wei kongbai haha", vms[0].getMessage());
	}

 

可以看到虽然user.setNumber("222-222-3");user.setUserName("    ");都不符合要求,但我们只通过方法cv.getInvalidValues(user, "userName");验证了userName一个属性,所以最后只有一个错误。

验证一个属性:
Hibernate Validator也可以只单独直接验证一个属性,看下面的测试用例:

public void testOneProperty() {
		ClassValidator cv = new ClassValidator(User.class, ResourceBundle
				.getBundle("vmessages"));
		String userName = "    ";
		InvalidValue[] vms = cv.getPotentialInvalidValues("userName", userName);
		assertEquals(1, vms.length);
		assertEquals("buenng wei kongbai haha", vms[0].getMessage());
	}

 

我们不需要创建User对象,就可以使用User对象里面设置的验证规则直接去验证一个值。很适合验证HttpServletRequest传入的单个参数到PO中的情况。

 
 

(阅读 )   评论数(:6)
评论】 【收藏】
评论:共6条
不错。
评论人: 天一     评论时间: 2008-01-11 11:18:07
Hibernate什么时候开始借鉴JWEB的思想了。
评论人: lengyu     评论时间: 2008-01-11 14:40:48
lengyu, Hibernate-validator是符合JSR的。 验证现在JCP也有个标准的
评论人: 匿名用户     评论时间: 2008-01-11 15:04:46
评论人: 匿名用户     评论时间: 2008-03-02 11:21:44
You rellay saved my skin with this information. Thanks!
评论人: YmotGLWgvovYwneZWs     评论时间: 2013-02-28 09:41:25
OWyey3  <a href="http://btlyvayzstwe.com/">btlyvayzstwe</a>
评论人: hKrbeKzXmGcJNDuDm     评论时间: 2013-03-01 11:09:56

发表评论:
发表人:
评论: 
验证码:
请输入前面图中的四位验证码,字母不区分大小写
  
 
关于我们 | 诚聘英才 | 联系我们 | 广告业务 | 网站地图 | 法律声明

EasyJF开源团队版权所有  建议使用1024*768分辨率