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