考虑将验证作为业务逻辑是有利有弊,Spring 提供了一种验证(和数据绑定)设计,但并不排除其中任何一个。具体来说,验证不应与网络层绑定,并且应该易于本地化,并且应该可以插入任何可用的验证器。考虑到这些问题,Spring 提供了一个Validator
接口,该接口既基本又可以在应用程序的每一层使用。
数据绑定对于使用户 Importing 动态绑定到应用程序(或用于处理用户 Importing 的任何对象)域模型很有用。 Spring 提供了恰当地命名为DataBinder
的名称。 Validator
和DataBinder
组成了validation
程序包,该程序包主要用于但不限于 MVC 框架。
BeanWrapper
是 Spring 框架中的一个基本概念,在很多地方都使用过。但是,您可能不需要直接使用BeanWrapper
。但是,由于这是参考文档,因此我们认为可能需要进行一些解释。我们将在本章中解释BeanWrapper
,因为如果您将要使用它,则在尝试将数据绑定到对象时最有可能使用它。
Spring 的DataBinder
和较低级别的BeanWrapper
都使用PropertyEditorSupport
实现来解析和格式化属性值。 PropertyEditor
和PropertyEditorSupport
接口是 JavaBeans 规范的一部分,本章还将对此进行说明。 Spring 3 引入了core.convert
软件包,该软件包提供了常规的类型转换工具,以及用于格式化 UI 字段值的高级“格式”软件包。您可以将这些软件包用作PropertyEditorSupport
实现的更简单替代方案。本章还将对它们进行讨论。
JSR-303/JSR-349 Bean 验证
从 4.0 版本开始,Spring 框架支持 Bean 验证 1.0(JSR-303)和 Bean 验证 1.1(JSR-349),以支持设置并使其适应 Spring 的Validator
接口。
应用程序可以选择一次全局启用 Bean 验证(如Spring Validation中所述),并将其专用于所有验证需求。
应用程序还可以为每个DataBinder
实例注册其他 Spring Validator
实例,如配置一个 DataBinder中所述。
Spring 具有Validator
接口,可用于验证对象。 Validator
接口通过使用Errors
对象工作,因此验证器可以在验证时向Errors
对象报告验证失败。
考虑以下小型数据对象的示例:
public class Person { private String name; private int age; // the usual getters and setters... }
下一个示例通过实现org.springframework.validation.Validator
接口的以下两种方法来提供Person
类的验证行为:
supports(Class)
:此Validator
是否可以验证提供的Class
的实例?
validate(Object, org.springframework.validation.Errors)
:验证给定的对象,并在验证错误的情况下,将其注册到给定的Errors
对象。
实现Validator
非常简单,尤其是当您知道 Spring 框架还提供的ValidationUtils
helper 类时。以下示例为Person
实例实现Validator
:
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"); } } }
ValidationUtils
类上的static
rejectIfEmpty(..)
方法用于拒绝name
属性(如果它是null
或空字符串)。
虽然可以实现单个Validator
类来验证丰富对象中的每个嵌套对象,但是最好将每个嵌套类的验证逻辑封装在自己的Validator
实现中。一个“丰富”对象的简单示例是一个Customer
,它由两个String
属性(名字和第二个名称)和一个复杂的Address
对象组成。 Address
对象可以独立于Customer
对象使用,因此已实现了不同的AddressValidator
。如果希望CustomerValidator
重用AddressValidator
类中包含的逻辑而不求助于复制和粘贴,则可以在CustomerValidator
中依赖注入或实例化AddressValidator
,如以下示例所示:
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();
}
}
}
验证错误会报告给传递给验证器的Errors
对象。对于 Spring Web MVC,可以使用<spring:bind/>
标签检查错误消息,但是也可以自己检查Errors
对象。
我们介绍了数据绑定和验证。本节介绍与验证错误相对应的输出消息。在preceding section所示的示例中,我们拒绝了name
和age
字段。如果要使用MessageSource
输出错误消息,可以使用拒绝字段时提供的错误代码(在这种情况下为“名称”和“年龄”)进行输出。当您从Errors
接口调用(直接或间接使用ValidationUtils
类)rejectValue
或其他reject
方法时,基础实现不仅会注册您传入的代码,还会注册许多其他错误代码。 MessageCodesResolver
确定Errors
接口寄存器的错误代码。默认情况下,使用DefaultMessageCodesResolver
,例如,它不仅使用您提供的代码注册一条消息,而且还注册包含您传递给 reject 方法的字段名称的消息。因此,如果您使用rejectValue("age", "too.darn.old")
拒绝字段,除了too.darn.old
代码,Spring 还会注册too.darn.old.age
和too.darn.old.age.int
(第一个包含字段名称,第二个包含字段类型)。这样做是为了方便开发人员在定位错误消息时提供帮助。
org.springframework.beans
软件包遵循 JavaBeans 标准。 JavaBean 是具有默认无参数构造函数的类,并且遵循命名约定,其中(例如)名为bingoMadness
的属性将具有 setter 方法setBingoMadness(..)
和 getter 方法getBingoMadness()
。
Bean 包中的一个非常重要的类是BeanWrapper
接口及其相应的实现(BeanWrapperImpl
)。正如从 Javadoc 引用的那样,BeanWrapper
提供了以下功能:设置和获取属性值(单独或批量),获取属性 Descriptors 以及查询属性以确定它们是否可读或可写。此外,BeanWrapper
还支持嵌套属性,从而可以将子属性上的属性设置为无限深度。 BeanWrapper
还支持添加标准 JavaBean PropertyChangeListeners
和VetoableChangeListeners
的能力,而无需在目标类中支持代码。最后但并非最不重要的一点是,BeanWrapper
支持设置索引属性。 BeanWrapper
通常不直接由应用程序代码使用,而由DataBinder
和BeanFactory
使用。
BeanWrapper
的工作方式部分地由其名称表示:它包装一个 bean 以对该 bean 执行操作,例如设置和检索属性。
setPropertyValue
,setPropertyValues
,getPropertyValue
和getPropertyValues
方法,这些方法带有一些重载的变体。
原文:https://www.cnblogs.com/jrkl/p/14159233.html