在基於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