JSR 303 - Bean Validation - 为实体验证定义了元数据模型和API. 默认的元数据模型是通过Annotations来描述的,但是也可以使用XML来重载或者扩展. Bean Validation API 并不局限于应用程序的某一层或者哪种编程模型, Bean Validation 可以被用在任何一层, 或者是像类似Swing的富客户端程序中.
Hibernate Validate 4 是Bean Validate 最好的实现.这里主要讲Hibernate Validate 在Spring MVC 中怎么去验证数据.Bean Validation 的约束是通过Java注解(annotations)来标注的.约束条件能够被标注在类的字段,属性,方法以及类上面,没有对象可以有多个约束.当约束被定义在字段上的时候,这个字段的值是通过字段访问策略来获取并验证的.也就是说Bean Validation的实现者会直接访问这个实例变量而不会调用属性的访问器(getter)即使这个方法存在.(静态字段或者属性是不会被校验的.这个字段的访问级别( private,protected 或者 public) 对此没有影响.)
通常的属性,方法,字段的约束有:
@AssertFalse Checks thatthe annotated element is false.
@AssertTrue Checks thatthe annotated element is true.
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.
@Digits(integer=,fraction=)Checks whetherthe annoted value is a number having up to integer digitsand fraction fractional digits.
@Future 检查给定的日期是否比现在晚.
@Max 检查该值是否小于或等于约束条件中指定的最大值.
@Min 检查该值是否大于或等于约束条件中规定的最小值.
@NotNull Checks thatthe annotated value is not null.
@Null Checks thatthe annotated value is null.
@Past检查标注对象中的值表示的日期比当前早.
@Pattern(regex=,flag=) 检查该字符串是否能够在match指定的情况下被regex定义的正则表达式匹配.
@Size(min=, max=) Checks ifthe annotated element's size is between min andmax (inclusive).
@Valid递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email Checks whetherthe specified string is a valid email address.
@Length(min=,max=)Validates that the annotated string is between min andmax included.
@NotBlank检查约束字符串是不是Null还有被Trim的长度是否大于0,与@NoEmpty不同的是该约束只对字符串且会自动忽略尾空格.
@NotEmpty检查约束元素是否为NULL或者是EMPTY.
@Range(min=,max=)Checks whether the annotated value lies between (inclusive)the specified minimum and maximum.
@ScriptAssert(lang= ,script=,alias=)
@URL(protocol=,host=,port=,regexp=, flags=)
验证组
验证组就是把一个域模型对象中的验证规则划分到不同的组别,分开验证,这对于复杂的业务情况很有用。每一个约束注解都有一个groups属性,用于指定一个接口的Class对象,没有传递这个组别参数的约束也就是默认为javax.validation.groups.Default。一旦一个约束注解使用了groups 属性,那么它将不再属于默认的组别。其实每一个组别就是一个空的接口,这里为什么使用接口而不是字符串呢?因为字符串不能被编译器识别。例如:某个组别改变了,使用接口,编译器会编译出错,这样就会提醒你改变原来的组别。如果要是字符串呢?那就很麻烦了,你需要找遍所有的JAVA 源文件,去改曾经用过的组别字符串名称。
(1)组别序列组别序列可以把一系列的组别按照一定的顺序排列在一起,然后逐个验证,只要有一个组别验证失败,就不继续验证剩余的组别。使用javax.validation.GroupSequence的好处是验证顺序有了保证,另外,“短路”验证也可以生效,也就是只要遇到不合法的约束,就不继续其他的约束验证。但要注意的是验证序列中的引用关系不要形成闭环,也就是G3里包含G1、G2,而G1里又包含G3,这样就会形成死循环,JSR 303会抛出javax.validation.GroupDefinitionException异常。
(2)覆盖javax.validation. groups.Default如果你想覆盖默认的 Default 验证,那么可以在验证的类上使用@GroupSequence 注解,但要注意序列中必须包含当前的类,且不能包含 Default组别。
Spring MVC中应用Hibernate Validate:
1.User.class
@GroupSequence({ User.class, GroupB.class, GroupC.class })
public class User {
@NotEmpty(message = "用户名不能为空")
private String name;// message可以用来指定ErrorMessage.否则由Hibernate Validate默认.
@NotEmpty(message = "密码不能为空")
@Size(min = 4, max = 20, message = "密码长度必须在{min}-{max}范围内", groups = GroupB.class)
private String password;
// setter andgetter
}
interface GroupB {
}
interface GroupC {
}
@NotEmpty没有定义Group,则为默认的User.class组,则会优先验证,如果不通过则不会继续验证GroupB.class组的,以及GroupC.class组的.
2.Controller中方法的处理.
@RequestMapping(method =RequestMethod.POST)
public ModelAndViewaddUser(@Valid User user,BindingResult result){
//@Valid Useruser 会将验证user,然后把结果赋值给result.当参数传进来.
...
if(result.hasFieldErrors()){ //判断验证是否出错.
List<FieldError> fes= result.getFieldErrors();
for(FieldError fe : fes){
System.out.println("FieldError : "+fe.getField()+" :"+fe.getDefaultMessage());
//getField()获取出错的对象名.
//getDefaultMessage()获取出错的信息.
model.put(fe.getField()+"msg",fe.getDefaultMessage());
}
}
...
return ... ;
}