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 社群中所有即將發生的活動。

檢視全部