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

    结果如下图所示:
在这里插入图片描述
    提交后格式化结果如下:
在这里插入图片描述
    数据已经被格式化并输出在视图页面当中。

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