使用 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)
)。