Validation by Using Spring’s Validator Interface
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)
)。