在基于SpringMVC框架的开发中,我们经常要对用户提交的字段进行合法性验证,比如整数类型的字段有个范围约束,我们会用@Range(min=1, max=4)
。在实际应用开发中,我们经常碰到一些自己业务的场景要自定义一些验证规则,而这是标准的JSR-303
和Hibernate Validation
所不具备的,所以我们就要根据JSR-303
的规范来扩展我们自定义的验证规则注释
.
假设我们现在有个接口要接收一个手机
的字段, 它的约束规则是13位数字字符. 我们可以通过正则表达式完成: ^\d{13}$
来验证. 下面是个javabean代码:
public class Person{
@Phone
private String phone;
}
我们再来看下@Phone
的代码.
@Documented
@Constraint(validatedBy = PhoneConstraintValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Phone {
String message() default "{Phone}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
这个注解类看起来复杂, 其实不然. 因为这基本上每个扩展验证注解都必需定义的三个方法, 是规范定义的, 所以我们可以像个模板一样copy过来改下. 这里要注意的是这个message
方法, 定义了如果验证出错时要显示的消息内容. 对于消息格式和规范, 可以使用标准的Spring Message Resource Bindle
来, 可以参考这篇. 现在定义了注解, 正如你所料, 我们要定义下具体的业务规则:
public class PhoneConstraintValidator implements ConstraintValidator<Phone, String> {
@Override
public void initialize(Phone phone) { }
@Override
public boolean isValid(String phoneField, ConstraintValidatorContext cxt) {
if(phoneField == null) {
return false;
}
return phoneField.matches("^\d{13}$");
}
}
所有验证规则方法类都要实现ConstraintValidator<V,F>
这个接口, 里面第一个方法initialize
的参数是所关联的注解对象, 所以这个方法里可以取出使用注解的地方传进来的值, 后面一个例子会讲到这一点. 第二个最核心的方法isValid
第一个参数就是我们要验证的字段值, 大家看下上面的代码就知道怎样使用了.
下面我们来看第二种形式的注解. 假如我们对用户的生日字段进行验证, 限制只满足1989年出生的人。 如下:
public class Person {
@Year(1989)
private Date birthday;
// getters setters ...
}
现在自定义验证注解Year
有要传入一个参数, 用默认的value
方法接收:
@Documented
@Constraint(validatedBy = YearConstraintValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Year {
int value();
String message() default "{Year}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
还是要上面的一样, 要定义一个规则约束描述类:
public class YearConstraintValidator implements ConstraintValidator<Year, Date> {
private int annotationYear;
@Override
public void initialize(Year year) {
this.annotationYear = year.value();
}
@Override
public boolean isValid(Date target, ConstraintValidatorContext cxt) {
if(target == null) {
return true;
}
Calendar c = Calendar.getInstance();
c.setTime(target);
int fieldYear = c.get(Calendar.YEAR);
return fieldYear == annotationYear;
}
}
可以看到initiallize
方法中可以接收关联的注解Year
, 这里可以取出里面的参数信息用于约束规则方法调用.
原文: http://www.javacodegeeks.com/2013/07/spring-mvc-custom-validation-annotations.html