Spring MVC 入門(八)Spring MVC 數據格式化

8.1 數據格式化

    如何從格式化的數據中獲取真正的數據以完成數據綁定,並將處理完成的數據輸出爲格式化的數據是 Spring 格式化框架需要解決的問題。Spring 從 3.0 開始引入格式化轉換框架,該框架位於 org.springframework.format 包。其中,最重要的是 Formatter<T> 接口。
    Formatter 完成任意 Object 與 String 之間的類型轉換,即格式化和解析,其支持細粒度和字段級別的格式化/解析。Formatter 只能將 String 轉換成另一種 Java 類型,因此 Formatter 更適用於 Web 層的數據轉換。

8.1.1 使用 Formatter 格式化數據

  1. 創建 DateFormatter 類,實現 org.springframework.format.Formatter 接口。
package formatter;

import org.springframework.format.Formatter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
// 實現接口。
public class DateFormatter implements Formatter<Date> {

    // 日期類型模板:如 yyyy-MM-dd。
    private String datePattern;
    // 日期格式化對象。
    private SimpleDateFormat dateFormat;
    // 構造器,通過依賴注入的日期類型創建日期格式化對象。

    public DateFormatter(String datePattern){
        this.datePattern = datePattern;
        this.dateFormat = new SimpleDateFormat(datePattern);
    }

    // 解析文本字符串,返回一個 Formatter<T> 的 T 類型對象。
    @Override
    public Date parse(String source, Locale locale) throws ParseException {
        try{
            return dateFormat.parse(source);
        }catch (Exception e){
            throw new IllegalArgumentException();
        }
    }

    // 顯示 Formatter<T> 的 T 類型對象。
    @Override
    public String print(Date date, Locale locale) {
        return dateFormat.format(date);
    }
}

    DateFormatter 類實現了接口中的兩個方法:parse 方法,使用指定的 Locale 將一個 String 解析成目標 T 類型;print 方法,用於返回 T 類型的字符串表示形式。DateFormatter 類中使用了 SimpleDateFormat 對象將 String 轉換成 Date 類型,日期類型模板 yyyy-MM-dd 之後會通過配置文件的依賴注入設置。

  1. 在 Spring MVC 配置文件中加入自定義格式化轉換器。
<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="controller"/>
    <!--  裝配自定義的類型轉換器  -->
    <mvc:annotation-driven conversion-service="conversionService"/>
    <!--  自定義的類型轉換器  -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatters">
            <list>
                <bean class="formatter.DateFormatter" c:_0="yyyy-MM-dd"/>
            </list>
        </property>
    </bean>
    <!--  使用默認的 Servlet 來響應靜態文件  -->
    <mvc:default-servlet-handler/>
    <!--  視圖解析器  -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--    前綴    -->
        <property name="prefix">
            <value>/WEB-INF/content/</value>
        </property>
        <!--    後綴    -->
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>

    Spring 在格式化模塊中定義了一個實現 ConversionService 接口的 FormattingConversionServece 實現類,該類既具有類型轉換功能,又具有格式化的功能。而 FormattingConversionServiceFactoryBean 工廠類正是用於 Spring 上下文中構造一個 FormattingConversionService 對象,通過這個工廠類,既可以註冊自定義的轉換器,還可以註冊自定義的註解驅動邏輯。
    以上配置使用 FormattingConversionServiceFactoryBean 對自定義的格式轉換器 DateFormatter 進行了註冊。FormattingConversionServiceFactoryBean 類有一個屬性 converters。可以用它註冊 Converter;有一個屬性 formatters ,可以用它註冊 Formatter。
    注:<mvc:annotation-driven/>標籤內部默認創建的 ConversionService 實例 就是一個 FormattingConversionServiceFactoryBean,有了 FormattingConversionServiceFactoryBean 之後,Spring MVC 對處理方法的參數就綁定格式化功能了。
    Spring 本身提供了很多常用的 Formatter 實現。在 org.springframework.format.datetime 包中提供了一個用於時間對象格式化的 DateFormatter 實現類。
    在 org.springframework.format.number 包中提供了3個用於數字對象格式化的實現類:

  • NumberFormatter。用於數字類型對象的格式化。
  • CurrencyFormatter。用於貨幣類型對象的格式化。
  • PercentFormatter。用於百分數數字類型對象的格式化。

8.1.2 使用 FormatterRegistrar 註冊 Formatter

    註冊 Formatter 的另一種方法是使用 FormatterRegistrar。

  1. 新建 MyFormatterRegistrar 類,實現 FormatterRegistrar 接口,只需要實現一個 registerFormatters 方法,在該方法中添加需要註冊的 Formatter。
package formatter;

import org.springframework.format.FormatterRegistrar;
import org.springframework.format.FormatterRegistry;

public class MyFormatterRegistrar implements FormatterRegistrar {
    private DateFormatter dateFormatter;
    public void setDateFormatter(DateFormatter dateFormatter){
        this.dateFormatter = dateFormatter;
    }
    @Override
    public void registerFormatters(FormatterRegistry formatterRegistry) {
        formatterRegistry.addFormatter(dateFormatter);
    }
}
  1. 修改 Spring MVC 配置文件,註冊 Registrar。
<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="controller"/>
    <!--  裝配自定義的類型轉換器  -->
    <mvc:annotation-driven conversion-service="conversionService"/>
    <bean id="dateFormatter" class="formatter.DateFormatter" c:_0="yyyy-MM-dd"/>
    <!--  自定義的類型轉換器  -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatterRegistrars">
            <set>
                <bean class="formatter.MyFormatterRegistrar" p:dateFormatter-ref="dateFormatter"/>
            </set>
        </property>
    </bean>
    <!--  使用默認的 Servlet 來響應靜態文件  -->
    <mvc:default-servlet-handler/>
    <!--  視圖解析器  -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--    前綴    -->
        <property name="prefix">
            <value>/WEB-INF/content/</value>
        </property>
        <!--    後綴    -->
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>

8.2.1 使用 AnnotationFormatterFactory<A extends Annotation> 格式化數據

    Spring 爲開發者提供了註解驅動的屬性對象格式化功能;在 Bean 屬性中設置、Spring MVC 處理方法參數綁定數據、模型數據輸出時自動通過註解應用格式化的功能。
    在 org.springframework.format.annotation 包下面定義了兩個格式化的註解類型:

1. DateTimeFormat
    @DateTimeFormat 註解可以對 java.util.Date、java.util.Calendar 等時間類型的屬性進行標註。它支持以下幾個互斥的屬性:

  • iso。類型爲 DateTimeFormat.ISO。以下是幾個常用的可選值。
    DateTimeFormat.ISO.DATE:格式爲 yyyy-MM-dd。
    DateTimeFormat.ISO.DATE_TIME:格式爲 yyyy-MM-dd hh:mm:ss .SSSZ。
    DateTimeFormat.ISO.TIME:格式爲 hh:mm:ss .SSSZ。
    DateTimeFormat.ISO.NONE:表示不使用 ISO 格式的時間。
  • pattern。類型爲 String,使用自定義的時間格式化字符串,如“yyyy-MM-dd hh:mm:ss”。
  • style。類型爲 String,通過樣式指定日期時間的格式,由兩位字符組成,第一位表示日期的樣式,第二位表示時間的格式,以下是幾個常用的可選值。
    S:短日期/時間的樣式。
    M:中日期/時間的樣式。
    L:長日期/時間的樣式。
    F:完整日期/時間的樣式。
    -:忽略日期/時間的樣式。

2. NumberFormat
    @NumberFormat 可對類似數字類型的屬性進行標註,它擁有兩個互斥的屬性,具體說明如下:

  • Pattern。類型爲 String,使用自定義的數字格式化串,如“##,###。##”
  • style。類型爲 NumberFormat.Style,以下是幾個常用的可選值:
    NumberFormat.CURRENCY:貨幣類型。
    NumberFormat.NUMBER:正常數字類型。
    NumberFormat.PERCENT:百分數類型。

8.2.2 示例:使用 AnnotationFormatterFactory<A extends Annotation> 格式化數據

  1. 新建測試表單 testForm.jsp。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>測試表單數據格式化</title>
</head>
<body>
    <form action="test" method="post">
        <table>
            <tr>
                <td><label>日期類型:</label></td>
                <td><input type="text" id="birthday" name="birthday"></td>
            </tr>
            <tr>
                <td><label>整數類型:</label></td>
                <td><input type="text" id="total" name="total"></td>
            </tr>
            <tr>
                <td><label>百分數類型:</label></td>
                <td><input type="text" id="discount" name="discount"></td>
            </tr>
            <tr>
                <td>貨幣類型:</td>
                <td><input type="text" id="money" name="money"></td>
            </tr>
            <tr>
                <td><input id="submit" type="submit" value="提交"></td>
            </tr>
        </table>
    </form>
</body>
</html>
  1. 新建 User 類負責接收頁面數據。
package domain;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;
import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    // 日期類型
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;
    // 正常數字類型
    @NumberFormat(style = NumberFormat.Style.NUMBER,pattern = "#,###")
    private int total;
    // 百分數類型
    @NumberFormat(style = NumberFormat.Style.PERCENT)
    private double discount;
    // 貨幣類型
    @NumberFormat(style = NumberFormat.Style.CURRENCY)
    private double money;

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public double getDiscount() {
        return discount;
    }

    public void setDiscount(double discount) {
        this.discount = discount;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

    User 類的多個屬性使用了 DateTimeFormat 和 NumberFormat 註解,用於將頁面傳遞的 String 轉換成對應的格式化數據。

  1. 創建 UserController 類控制頁面跳轉。
package controller;

import domain.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class UserController {
    private static final Log logger = LogFactory.getLog(UserController.class);
    @RequestMapping(value = "/{formName}")
    public String loginForm(@PathVariable String formName){
        //動態跳轉頁面
        return formName;
    }
    @RequestMapping(value = "/test",method = RequestMethod.POST)
    public String test(@ModelAttribute User user, Model model){
        logger.info(user);
        model.addAttribute("user",user);
        return "success";
    }
}
  1. 新建 success.jsp 頁面顯示格式化後的數據。
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>測試表單數據格式化</title>
</head>
<body>
    <form:form modelAttribute="user" method="post" action="">
        <table>
            <tr>
                <td>日期類型:</td>
                <td><form:input path="birthday"/></td>
            </tr>
            <tr>
                <td>整數類型:</td>
                <td><form:input path="total"/></td>
            </tr>
            <tr>
                <td>百分數類型:</td>
                <td><form:input path="discount"/></td>
            </tr>
            <tr>
                <td>貨幣類型:</td>
                <td><form:input path="money"/></td>
            </tr>
        </table>
    </form:form>
</body>
</html>

    如果希望在視圖頁面中將模型屬性數據以格式化的方式進行渲染,則需要使用 Spring 的頁面標籤顯示模型數據。所以 success.jsp 中使用了 <form:form modelAttribute="user" > 標籤,並且綁定了 User 對象。

  1. 修改 Spring MVC 配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="controller"/>
    <!--  裝配自定義的類型轉換器  -->
    <mvc:annotation-driven/>
    <!--  使用默認的 Servlet 來響應靜態文件  -->
    <mvc:default-servlet-handler/>
    <!--  視圖解析器  -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--    前綴    -->
        <property name="prefix">
            <value>/WEB-INF/</value>
        </property>
        <!--    後綴    -->
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>

    在配置文件中只是使用了默認的 <mvc:annotation-driven/> 標籤,該標籤內部默認創建的 ConversionService 實例就是一個 FormattingConversionServiceFactoryBean,這樣就可以支持註解驅動的格式化功能了。

  1. 修改 web.xml 配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  1. 部署 Web 應用。
    在瀏覽器中輸入如下 URL 來測試應用:
http://localhost:8080/AnnotationFormatterTest/testForm

    結果如下圖所示:
在這裏插入圖片描述
    提交後格式化結果如下:
在這裏插入圖片描述
    數據已經被格式化並輸出在視圖頁面當中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章