Hibernate-validator是JSR303的一个实现。JSR303中定义了一种可以用Annotation来验证EntityBean信息 有效性的方式。虽然叫Hibernate-validator,但它是一个单独的jar文件,完全可以脱离Hibernate使用和扩展。
其依赖于”validation-api.jar”,”slf4j-api.jar”,”jaxb-api.jar”以及”jaxb-impl.jar”。
Maven项目可配置:
1 2 3 4 5 |
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.0.2.GA</version> </dependency> |
Hibernate-validator本身提供了诸多基本的验证比如,非空,长度,最大最小值,Email、RUL格式,范围,正则表达式等。如下:
@NotNull 验证非null。
@NotBlank 验证字符串非null,且长度必须大于0。
@Size(min=,max=) 验证元素是否在min和max之间的,可用于验证字段长度,和集合个数。
@Min 验证元素的值一定大于min指定的值。
@Max 验证元素的值一定小于max指定的值。
@Length(min=,max=) 验证字符串长度是否在min和max之间.
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Email 验证字符串是否是合法的Email格式.
@URL(protocol=,host=,port=) 验证字符串是否是合法的URL格式.
@Range(min=,max=) 验证指定元素的值是否在指定范围之内。
@Pattern(regex=,flag=) 根据指定的正则表达式来做特殊格式字符串的验证。
……
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Bean { @NotNull(message="not_null.bean.name") @Size(min=5,max=10,message="length.bean.name") private String name; @Digits(integer=3,fraction=4,message="digits.bean.num") private String num; @NotNull(message="not_null.bean.pass") @Length(min=6,max=12,message="length.bean.pass") private String pass; @NotNull(message="not_null.bean.age") @Max(60) @Min(10) private Integer age; @Email(message="email.bean.email") private String email; @Range(min=10000,max=50000,message="range.bean.wage") private BigDecimal wage; } |
每个Annotation都能指定message属性,这是在验证不通过时返回的信息。
定义了EntityBean并加入Annotation后,我们可以在验证的类中使用如下方式来对Bean进行验证:
1 2 3 4 5 6 7 |
ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); Set<ConstraintViolation<Pojo>> constraintViolations = validator.validate(pojo); for(Iterator<ConstraintViolation<Pojo>> i = constraintViolations.iterator(); i.hasNext();) { ConstraintViolation<Pojo> v = i.next(); System.out.println(v.getMessage()); } |
然而在很多情况下,上述验证并不能够完成我们的需求。在业务流程中会出现一些更加复杂的验证,如:当字段A为”Y”时,字段B必须不为空;或者当字段A- D中,要么A和B的总长度大于10,要么C和D的总长度大于10,否则返回错误。诸如这种情况,我们需要自定义一个Annotation来专门处理。
首先,定义一个Annotation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@Retention(RUNTIME) @Constraint(validatedBy=JointNotNullValidator.class) @Documented public @interface JointNotNull { String message() default "{com.hp.validator.jointNotNull}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } @Constraint 指定了具体处理验证过程的类。如下再定义一个处理类:JointNotNullValidator。 public class JointNotNullValidator implements ConstraintValidator<JointNotNull, Object> { public boolean isValid(Object obj, ConstraintValidatorContext constraintContext) { if(obj instanceof TestOBJ) { TestOBJ testOBJ = (TestOBJ)obj; if((testOBJ.getA()!=null&& testOBJ.getA().equals("Y")) && (testOBJ.getB()==null || testOBJ.getB().length()==0)) { return false; } return true; } return false; } public void initialize(JointNotNull joindNull) { } } |
处理类需要去继承ConstraintValidator接口,第一个泛型指定当前处理类属于哪个Annotation,第二个泛型指定被注解的Bean 类型。在isValid方法中实现具体的验证逻辑,即:当TestOBJ中的A为”Y”时,B必须不为空。initialize方法则可以做一些初始化操 作,比如获取调用者给定的value值和message值,都可以通过传入的参数(所属的Annotation对象)中得到。这样在有些验证中就能依赖于 给定的属性来做处理。
完成后,就能将@JointNotNull 同其他Annotation一样使用了。
有个注意点:
在定义Annotation时可以定义@Target属性,如:
1 2 3 4 5 6 7 8 9 10 11 |
@Target( { METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy=TodayValidator.class) @Documented public @interface Today { String message() default "{com.hp.validator.today}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } |
@Target其实是限制了当前Annotation的使用范围,比如现在这个就只能被用在方法,字段,和其它Annotation上,而不能放在类上。 如果被放在了字段上,那么在具体验证类中isValid方法的第一个参数被传入的就是被注解的字段对象,但如果放在了类上,那么isValid中得到的就 是整个类对象。而后者可以轻易得到这个类中其它字段的信息,以便解决需要依赖其它字段来做验证的情况,前者就只能对当前字段做验证,无法获取到其它字段信 息。
因为验证的调用代码都是一样的,可以将其放到一个类中,由Spring的AOP做切面逻辑。这样只要做一个封装,我们就能将整个项目的验证都抽离到一个模块中做统一的验证管理,而在业务方法中就不需要再考虑参数验证问题了,可以更专注于业务逻辑。