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