|
对于最新的稳定版本,请使用 Spring Framework 7.0.6! |
通过使用 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)
下一个示例通过实现 Person 类的以下两个方法,为 org.springframework.validation.Validator 接口提供验证行为:
-
supports(Class): 这个Validator可以验证提供的Class的实例吗? -
validate(Object, org.springframework.validation.Errors): 验证给定的对象 并在验证错误的情况下,将这些错误与给定的Errors对象一起注册。
实现一个 Validator 相对比较简单,尤其是当你知道 Spring 框架也提供了 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")
}
}
}
static rejectIfEmpty(..) 方法在 ValidationUtils 类上用于在 name 属性为 null 或空字符串时拒绝该属性。查看
ValidationUtils javadoc
以了解它除了之前显示的示例之外还提供了哪些功能。
虽然可以实现一个 Validator 类来验证丰富对象中的每个嵌套对象,但将每个嵌套类的验证逻辑封装在其自身的 Validator 实现中可能更好。一个简单的“丰富”对象示例是一个由两个 String 属性(名和姓)以及一个复杂的 Address 对象组成的 Customer。 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。