验证、数据绑定和类型转换
将验证视为业务逻辑有其优缺点,而Spring提供了一种验证和数据绑定的设计,这种设计并不排除这两种观点中的任何一种。具体来说,验证不应与Web层绑定,且应易于进行本地化;同时,应该能够插入任何可用的验证器。考虑到这些因素,Spring提供了一个Validator接口,该接口既基础又非常适用于应用程序的每一层。
数据绑定(Data Binding)有助于将用户输入动态地与应用程序的领域模型(或者用于处理用户输入的任何对象)关联起来。Spring提供了名为DataBinder的工具来实现这一功能。Validator和DataBinder共同组成了validation包,该包主要应用于(但不限于)Web层。
BeanWrapper是Spring框架中的一个基本概念,在很多地方都会用到。然而,你可能并不需要直接使用BeanWrapper。不过,由于这是参考文档,我们认为还是有必要做一些解释。在这一章中,我们会对BeanWrapper进行说明,因为如果你确实需要使用它的话,很可能是在尝试将数据绑定到对象的时候。
Spring的DataBinder和更低层的BeanWrapper都使用PropertyEditorSupport实现来解析和格式化属性值。PropertyEditor和PropertyEditorSupport类型是JavaBeans规范的一部分,在本章中也有介绍。Spring的core.convert包提供了一般的类型转换功能,还有一个更高级的format包用于格式化UI字段值。你可以使用这些包作为PropertyEditorSupport实现的简化替代方案。这些内容在本章也会有讨论。
Spring 通过设置基础设施和适配器来支持 Java Bean Validation,这些适配器与 Spring 自带的 Validator 接口相匹配。应用程序可以像 Java Bean Validation 中描述的那样全局启用 Bean Validation,并将其专门用于所有验证需求。在 Web 层,应用程序还可以根据每个 DataBinder 注册控制器本地的 Spring Validator 实例,如 配置 DataBinder 中所述,这对于插入自定义验证逻辑非常有用。
部分总结
📄️ 使用Spring的Validator接口进行验证
Spring 提供了一个 Validator 接口,你可以使用它来验证对象。Validator 接口通过使用 Errors 对象来工作,这样在验证过程中,验证器可以将验证失败的信息报告给 Errors 对象。
📄️ 数据绑定
数据绑定对于将用户输入与目标对象进行绑定非常有用,其中用户输入是一个以属性路径作为键的映射(map),遵循JavaBeans的约定。DataBinder是支持这一功能的主要类,它提供了两种方式来绑定用户输入:
📄️ 将错误代码解析为错误信息
我们已经讨论了数据绑定和验证。本节将介绍如何输出与验证错误相对应的消息。在前一节展示的示例中,我们拒绝了“name”和“age”这两个字段。如果我们想使用MessageSource来输出错误消息,就可以通过我们在拒绝字段时提供的错误代码来实现(本例中为“name”和“age”)。当你调用rejectValue方法或Errors接口中的其他拒绝方法(无论是直接调用还是间接调用,例如通过ValidationUtils类)时,底层实现不仅会注册你传递的错误代码,还会注册一些额外的错误代码。MessageCodesResolver负责确定Errors接口所注册的错误代码。默认情况下,使用的是DefaultMessageCodesResolver,它不仅会注册你提供的错误代码,还会注册包含字段名称的消息(这些消息中也包含传递给reject方法的字段名称)。因此,如果你使用rejectValue(\"age\", \"too.darn.old\")来拒绝一个字段,除了“too.darn.old”这个错误代码外,Spring还会注册“too.darn.old.age”和“too.darn.old.age.int”这两个错误代码(前者包含字段名称,后者包含字段类型)。这样做的目的是为了方便开发者查看错误信息。
📄️ Spring类型转换
core.convert包提供了一个通用的类型转换系统。该系统定义了一个SPI(Service Provider Interface)来实现类型转换逻辑,以及一个API来在运行时执行类型转换。在Spring容器内部,你可以使用这个系统作为PropertyEditor实现的替代方案,将外部化的bean属性值字符串转换为所需的属性类型。你也可以在应用程序中任何需要类型转换的地方使用这个公共API。
📄️ Spring字段格式化
如前一节所讨论的,core.convert是一个通用的类型转换系统。它提供了一个统一的ConversionService API,以及一个强类型的Converter SPI,用于实现从一种类型到另一种类型的转换逻辑。Spring容器使用这个系统来绑定bean属性的值。此外,Spring表达式语言(SpEL)和DataBinder也使用这个系统来绑定字段值。例如,当SpEL需要将Short强制转换为Long以完成expression.setValue(Object bean, Object value)的操作时,core.convert系统会执行这种强制转换。
📄️ 配置全局日期和时间格式
默认情况下,未使用 @DateTimeFormat 注解的日期和时间字段会使用 DateFormat.SHORT 格式从字符串进行转换。如果你有特殊需求,可以定义自己的全局格式来更改这一设置。
📄️ Java Bean Validation
Spring框架提供了对Java Bean Validation API的支持。