使用 Spring 的 Validator 介面進行驗證
Spring 提供了一個 Validator 介面,您可以使用它來驗證物件。Validator 介面透過使用 Errors 物件來工作,這樣在驗證過程中,驗證器可以將驗證失敗報告給 Errors 物件。
考慮以下小型資料物件的示例
-
Java
-
Kotlin
public class Person {
private String name;
private int age;
// the usual getters and setters...
}
class Person(val name: String, val age: Int)
下一個示例透過實現 org.springframework.validation.Validator 介面的以下兩個方法為 Person 類提供驗證行為
-
supports(Class):此Validator能否驗證所提供Class的例項? -
validate(Object, org.springframework.validation.Errors):驗證給定物件,如果存在驗證錯誤,則將其註冊到給定的Errors物件中。
實現 Validator 相當簡單,特別是當您瞭解 Spring Framework 也提供的 ValidationUtils 幫助類時。以下示例為 Person 例項實現了 Validator
-
Java
-
Kotlin
public class PersonValidator implements Validator {
/**
* This Validator validates only Person instances
*/
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
}
}
class PersonValidator : Validator {
/**
* This Validator validates only Person instances
*/
override fun supports(clazz: Class<*>): Boolean {
return Person::class.java == clazz
}
override fun validate(obj: Any, e: Errors) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty")
val p = obj as Person
if (p.age < 0) {
e.rejectValue("age", "negativevalue")
} else if (p.age > 110) {
e.rejectValue("age", "too.darn.old")
}
}
}
ValidationUtils 類上的 static rejectIfEmpty(..) 方法用於在 name 屬性為 null 或空字串時拒絕它。請參閱 ValidationUtils javadoc 以瞭解它除了前面顯示的示例之外還提供了哪些功能。
雖然確實可以實現一個單獨的 Validator 類來驗證富物件中的每個巢狀物件,但更好的方法可能是將每個巢狀物件類的驗證邏輯封裝在其自己的 Validator 實現中。一個“富”物件的簡單示例是一個 Customer,它由兩個 String 屬性(姓和名)和一個複雜的 Address 物件組成。Address 物件可以獨立於 Customer 物件使用,因此已經實現了一個獨立的 AddressValidator。如果您希望您的 CustomerValidator 重用 AddressValidator 類中包含的邏輯而無需複製貼上,您可以在您的 CustomerValidator 中依賴注入或例項化一個 AddressValidator,如下例所示
-
Java
-
Kotlin
public class CustomerValidator implements Validator {
private final Validator addressValidator;
public CustomerValidator(Validator addressValidator) {
if (addressValidator == null) {
throw new IllegalArgumentException("The supplied [Validator] is " +
"required and must not be null.");
}
if (!addressValidator.supports(Address.class)) {
throw new IllegalArgumentException("The supplied [Validator] must " +
"support the validation of [Address] instances.");
}
this.addressValidator = addressValidator;
}
/**
* This Validator validates Customer instances, and any subclasses of Customer too
*/
public boolean supports(Class clazz) {
return Customer.class.isAssignableFrom(clazz);
}
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
Customer customer = (Customer) target;
try {
errors.pushNestedPath("address");
ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
} finally {
errors.popNestedPath();
}
}
}
class CustomerValidator(private val addressValidator: Validator) : Validator {
init {
if (addressValidator == null) {
throw IllegalArgumentException("The supplied [Validator] is required and must not be null.")
}
if (!addressValidator.supports(Address::class.java)) {
throw IllegalArgumentException("The supplied [Validator] must support the validation of [Address] instances.")
}
}
/*
* This Validator validates Customer instances, and any subclasses of Customer too
*/
override fun supports(clazz: Class<>): Boolean {
return Customer::class.java.isAssignableFrom(clazz)
}
override fun validate(target: Any, errors: Errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required")
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required")
val customer = target as Customer
try {
errors.pushNestedPath("address")
ValidationUtils.invokeValidator(this.addressValidator, customer.address, errors)
} finally {
errors.popNestedPath()
}
}
}
驗證錯誤將報告給傳遞給驗證器的 Errors 物件。在 Spring Web MVC 的情況下,您可以使用 <spring:bind/> 標籤來檢查錯誤訊息,但您也可以自己檢查 Errors 物件。有關它提供的方法的更多資訊可以在 javadoc 中找到。
驗證器也可以在不涉及繫結過程的情況下,本地呼叫以立即驗證給定物件。從 6.1 版本開始,這透過新的 Validator.validateObject(Object) 方法得到了簡化,該方法現在預設可用,返回一個簡單的 Errors 表示,可以進行檢查:通常呼叫 hasErrors() 或新的 failOnError 方法將錯誤摘要訊息轉換為異常(例如,validator.validateObject(myObject).failOnError(IllegalArgumentException::new))。