[譯]SpringMVC自定義驗證註解(SpringMVC custom validation annotations)

海鳥發表於2014-10-25

在基於SpringMVC框架的開發中,我們經常要對使用者提交的欄位進行合法性驗證,比如整數型別的欄位有個範圍約束,我們會用@Range(min=1, max=4)。在實際應用開發中,我們經常碰到一些自己業務的場景要自定義一些驗證規則,而這是標準的JSR-303Hibernate 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

相關文章