Spring 3 类型转换和验证

工程 | Keith Donald | 2009 年 11 月 17 日 | ...

Spring 3 的最终版本即将发布,这将是一个很棒的版本。在这篇博文中,我将带您了解 Spring 3 的一些类型转换和验证增强功能。无论您是开发传统的 Web 应用程序、桌面应用程序还是“下一代”RIA,数据绑定、类型转换和验证都是重要的领域。正如您将在本文中看到的那样,Spring 3 在这些领域都为您提供了重大升级,同时保持了与以前版本的向后兼容性。

新的系统目标

在介绍功能之前,我想首先强调一下我们在着手改进 Spring 3 的数据绑定系统时所设定的目标

  1. 提供一个无状态、强类型的类型转换器 SPI,以取代 JavaBean PropertyEditors
  2. 提供一个统一的类型转换 API,可在需要转换的任何地方使用,包括 Spring 的 DataBinder 和表达式语言
  3. 允许通过 Java 注解元数据驱动类型转换
  4. 通过注册合理的默认值并应用约定优于配置来简化操作
随着 Spring 3 最终版本的临近,我相信我们已经实现了每个目标。请继续阅读,由您来判断。

功能

Spring MVC 是第一个充分利用新类型转换系统的环境,我将从中提取内容来演示新功能。这从新的 Spring MVC 3 配置命名空间开始


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <mvc:annotation-driven />

</beans>

上面的最小配置会导致 Spring 自动安装默认类型转换器,这些转换器会本地化 Number 和 Date 字段,包括完全支持流行的 Joda Time 库(如果它存在于您的类路径中)。此外,如果 JSR-303 提供程序(例如 Hibernate Validator)存在于您的类路径中,Spring 还会自动启用注解驱动的声明式验证。

现在,当您绑定到字段时,该字段将使用合理的默认格式为用户的区域设置打印和解析。为了说明这一点,请考虑以下模型


public class Account {

    private Date activationDate = new Date(1258466400);

    private BigDecimal balance = new BigDecimal("3000.25");
}

... 在美国和德国区域设置的表单上打印

Locale.US Locale.DE
激活日期

余额

激活日期

余额

使用注解覆盖默认值

通常,您需要以不同于默认格式的方式格式化字段。在前面的示例中,您可能希望使用短日期格式格式化activationDate字段,并使用货币格式格式化balance字段。在以前版本的 Spring 中,您将在 Controller 中注册自定义 PropertyEditor 来实现此目的。在 Spring 3 中,您只需注解您的字段


private class Account {

    @DateTimeFormat(style="S-")
    private Date activationDate = new Date(1258466400);

    @NumberFormat(style=Style.CURRENCY)
    private BigDecimal balance = new BigDecimal("3000.25");
}

使用注解覆盖,以下内容将为美国和德国区域设置打印

Locale.US Locale.DE
激活日期

余额

激活日期

余额

参数注解

注解驱动的覆盖也可以应用于方法参数。考虑以下 Controller 方法,该方法获取特定日期的即将到来的约会,其中日期是 URL 路径变量,以 ISO 日期格式编码


    @RequestMapping(value = "/appointments/{day}", method = RequestMethod.GET)
    public String getAppointmentsForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day) {
        ...
    }

向 /appointments/2009-11-17 发送 GET 请求会获取 2009 年 11 月 17 日的所有约会。将 @DateTimeFormat 的 iso 属性设置为 ISO.DATE 指示 Spring 将传入的日期字符串解析为 ISO 日期 (yyyy-mm-dd)。

验证

通常在将用户输入绑定到模型后对其进行验证。Spring 3 提供对 JSR-303 声明式验证的支持。如果 JSR-303 提供程序(例如 Hibernate Validator)存在于您的类路径中,则会自动启用此支持。启用后,您只需使用 @Valid 注解来注解 Controller 方法参数即可触发验证


    @RequestMapping(value = "/appointments", method = RequestMethod.POST)
    public String add(@Valid AppointmentForm form, BindingResult result) {
        ....
    }

    static class AppointmentForm {

        @NotNull @Future
        private Date date;
    }

在绑定传入的 POST 参数后,将验证 AppointmentForm;在这种情况下,验证日期字段值是否不为 null 并且发生在未来。

约定优于配置

最后,考虑如何将约定优于配置的原则应用于类型转换。在业务应用程序中,您通常会定义自己的自定义字段类型。在以前版本的 Spring 中,要格式化此类类型,您将创建一个自定义 PropertyEditor 实现并在 Controller 中注册它。使用 Spring 3,在大多数情况下,您可以简单地遵守以下约定

  1. 定义一个静态 valueOf(String) 方法或 Constructor(String) 以从其 String 表示形式解析您的值
  2. 实现 toString() 以打印您的值以供显示

考虑一个符合此约定的 SocialSecurityNumber 类型


    public class SocialSecurityNumber {

        @Size(9)
        @Mask("###-##-####")
        private String value;

        public SocialSecurityNumber(String value) {
            this.value = value;
        }

        public String toString() {
            return this.value;
        }
    }

当 SocialSecurityNumber 字段被打印以供显示时,将调用 toString();当解析客户端值时,将调用 Constructor。不需要单独的 Formatter 或 PropertyEditor 实现。

总结

本文介绍了一些新的 Spring 3 类型转换和验证功能。要了解更多信息,包括如何实现自己的类型转换器,请查看 Spring 3 参考指南。此外,请关注未来几周发布的修订后的 Petclinic 3 示例应用程序(此示例应用程序演示了此处强调的所有功能,目前可以在我们的 SVN 存储库 here 中进行早期访问)。

我对这些新功能为我们提供的未来发展基础感到兴奋!请让我知道您在应用和扩展这些功能方面的经验,并在 jira.springframework.org 上继续提供反馈和想法。

获取 Spring 新闻简报

通过 Spring 新闻简报保持联系

订阅

抢先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将发生的活动

查看 Spring 社区中所有即将发生的活动。

查看全部