考虑将验证作为业务逻辑是有利有弊,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