对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

使用 Spring 的 Validator 接口进行验证

Spring 提供了一个 Validator 接口,可用于验证对象。Validator 接口通过使用一个 Errors 对象来工作,这样在验证过程中,验证器可以将验证失败信息报告给该 Errors 对象。spring-doc.cadn.net.cn

考虑以下小型数据对象的示例:spring-doc.cadn.net.cn

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 类提供了验证行为:spring-doc.cadn.net.cn

  • supports(Class):此 Validator 能否验证所提供的 Class 的实例?spring-doc.cadn.net.cn

  • validate(Object, org.springframework.validation.Errors):验证给定的对象,如果存在验证错误,则将这些错误注册到给定的 Errors 对象中。spring-doc.cadn.net.cn

实现一个 Validator 相当简单,特别是当你了解 Spring 框架还提供了 ValidationUtils 辅助类时。下面的示例为 Validator 实例实现了 Personspring-doc.cadn.net.cn

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, 了解除了前述示例之外它所提供的功能。spring-doc.cadn.net.cn

虽然当然可以实现一个单一的 Validator 类来验证丰富对象中的每个嵌套对象,但将每个嵌套对象类的验证逻辑封装在其自身的 Validator 实现中可能更好。一个“丰富”对象的简单示例是一个 Customer,它由两个 String 属性(名字和姓氏)以及一个复杂的 Address 对象组成。Address 对象可以独立于 Customer 对象使用,因此已实现了独立的 AddressValidator。如果您希望您的 CustomerValidator 重用 AddressValidator 类中包含的逻辑而不采用复制粘贴的方式,您可以像以下示例所示,在您的 CustomerValidator 中进行依赖注入或实例化一个 AddressValidatorspring-doc.cadn.net.cn

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 对象本身。有关它提供的方法的更多信息,请参见 javadocspring-doc.cadn.net.cn