spring 转换器和格式化
Spring总是试图用默认的语言区域将日期输入绑定 到java.util.Date。假如想让Spring使用不同的日期样 式,就需要用一个Converter(转换器)或者 Formatter(格式化)来协助Spring完成。
一. Converter
利用Converter进行日期的格式化
Spring的Converter是一个可以将一种类型转换成另 一种类型的对象。例如,用户输入的日期可能有许多种 形式,如“December 25,2014”“12/25/2014”“2014-12- 25” ,这些都表示同一个日期。默认情况下,Spring会 期待用户输入的日期样式与当前语言区域的日期样式相 同。例如,对于美国的用户而言,就是月/日/年格式。 如果希望Spring在将输入的日期字符串绑定到Date时, 使用不同的日期样式,则需要编写一个Converter,才能 将字符串转换成日期。
1. 日期格式化需要的类:org.springframework.core.convert.converter.Converter
需要实现org.springframework.core.convert.converter.Converter的接口
public interface Converter<S, T
例如
package converter; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.core.convert.converter.Converter; //必须实现 Converter public class StringToDateConverter implements Converter<String, Date> { private String datePattern; public StringToDateConverter(String datePattern) { this.datePattern = datePattern; System.out.println("instantiating .... converter with pattern:*" + datePattern); } // 转换日期格式
@Override public Date convert(String s) { try { SimpleDateFormat dateFormat = new SimpleDateFormat(datePattern); dateFormat.setLenient(false); return dateFormat.parse(s); } catch (ParseException e) { // the error message will be displayed when using // <form:errors> throw new IllegalArgumentException("invalid date format. Please use this pattern\"" + datePattern + "\""); } } }
2. springmvc-cofing.xml配置
<mvc:annotation-driven conversion-service="conversionService"/> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="converter.StringToDateConverter"> <constructor-arg type="java.lang.String" value="MM-dd-yyyy" /> </bean> </list> </property> </bean>
3.controller类
package controller; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import domain.Employee; @org.springframework.stereotype.Controller public class EmployeeController { private static final Log logger = LogFactory.getLog(EmployeeController.class); @RequestMapping(value="employee_input") public String inputEmployee(Model model) { model.addAttribute(new Employee()); return "EmployeeForm"; } @RequestMapping(value="employee_save") public String saveEmployee(@ModelAttribute Employee employee,BindingResult bindingResult,Model model) { if(bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); logger.info("Code:" + fieldError.getCode() + ", field:" + fieldError.getField()); } // save employee here model.addAttribute("employee",employee); return "EmployeeDetails"; } }
4.view视图
<%@ taglib prefix="form" uri="http://www.springframework.org/ta gs/form" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" % > <!DOCTYPE html> <html> <head> <title>Add Employee Form</title> <style type="text/css">@import url("<c:url value="/css/main.css"/>");</style> </head> <body> <div id="global"> <form:form commandName="employee" action="employee_save" method ="post"> <fieldset> <legend>Add an employee</legend> <p> <label for="firstName">First Name: </label> <form:input path="firstName" tabindex="1"/> </p> <p> <label for="lastName">First Name: </label> <form:input path="lastName" tabindex="2"/> </p> <p>
<!-- 打印错误 -->
<form:errors path="birthDate" cssClass="error"/> </p> <p> <label for="birthDate">Date Of Birth: </label> <form:input path="birthDate" tabindex="3" /> </p> <p id="buttons"> <input id="reset" type="reset" tabindex="4"> <input id="submit" type="submit" tabindex="5" value="Add Employee"> </p> </fieldset> </form:form> </div> </body> </html>
二. Formatter
Formatter就像Converter一样,也是将一种类型转换 成另一种类型。但是,Formatter的源类型必须是一个 String,而Converter则适用于任意的源类型。Formatter 更适合Web层,而Converter则可以用在任意层中。为了 转换Spring MVC应用程序表单中的用户输入,始终应 该选择Formatter,而不是Converter。
1. 为了创建Formatter,要编写一个实现 org.springframework.format.Formatter接口的Java类。下 面是这个接口的声明:
public interface Formatter<T >
这里的T表示输入字符串要转换的目标类型。该接 口有parse和print两个方法,所有实现都必须覆盖:
T parse(String text, java.util.Locale locale) String print(T object, java.util.Locale locale)
parse方法利用指定的Locale将一个String解析成目 标类型。print方法与之相反,它是返回目标对象的字符 串表示法。
例如,app20a应用程序中用一个DateFormatter将 String转换成Date
DateFormatter类
package fomatter; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import org.springframework.format.Formatter; public class DateFormatter implements Formatter<Date>{ private String datePattern; private SimpleDateFormat dateFormat; /* 这里的datepattern 从springmvc-config.xml传入 */ public DateFormatter(String datePattern) { this.datePattern = datePattern; dateFormat = new SimpleDateFormat(datePattern); dateFormat.setLenient(false); } @Override public String print(Date date, Locale locale) { return dateFormat.format(date); } @Override public Date parse(String s, Locale locale) throws ParseException { try { return dateFormat.parse(s); }catch(ParseException e) { // the error message will be displayed when using // <form:errors> throw new IllegalArgumentException( "invalid date format. Please use this pattern\"" + datePattern + "\""); } } }
app20b的Spring配置文件
<?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 http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置自定义扫描的包 --> <context:component-scan base-package="controller"> </context:component-scan> <context:component-scan base-package="formatter"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 和 后缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 转换器 --> <mvc:annotation-driven conversion-service="conversionService" /> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="formatters"> <set> <bean class="fomatter.DateFormatter"> <constructor-arg type="java.lang.String" value="MM-dd-yyyy" /> </bean> </set> </property> </bean> </beans>
EmployeeController类
package controller;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import domain.Employee;
@org.springframework.stereotype.Controller
public class EmployeeController {
private static final Log logger = LogFactory.getLog(EmployeeController.class);
@RequestMapping(value="employee_input")
public String inputEmployee(Model model) {
model.addAttribute(new Employee());
return "EmployeeForm";
}
@RequestMapping(value="employee_save")
public String saveEmployee(@ModelAttribute Employee employee,BindingResult bindingResult,Model model) {
if(bindingResult.hasErrors()) {
FieldError fieldError = bindingResult.getFieldError();
logger.info("Code:" + fieldError.getCode()
+ ", field:" + fieldError.getField());
}
// save employee here
model.addAttribute("employee",employee);
return "EmployeeDetails";
}
}
EmployeeForm.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html> <html> <head> <title>Add Employee Form</title> <style type="text/css"> @import url("<c:url value= "/css/main.css"/>"); </style> </head> <body> <div id="global"> <form:form modelAttribute="employee" action="employee_save" method="post"> <fieldset> <legend>Add an employee</legend> <p> <label for="firstName">First Name: </label> <form:input path="firstName" tabindex="1" /> </p> <p> <label for="lastName">First Name: </label> <form:input path="lastName" tabindex="2" /> </p> <p> <form:errors path="birthDate" cssClass="error" /> </p> <p> <label for="birthDate">Date Of Birth: </label> <form:input path="birthDate" tabindex="3" /> </p> <p id="buttons"> <input id="reset" type="reset" tabindex="4"> <input id="submit" type="submit" tabindex="5" value="Add Employee"> </p> </fieldset> </form:form> </div> </body> </html>
三. 用Registrar注册Formatter
注册Formatter的另一种方法是使用Registrar。例 如,以下app20b就是注册DateFormatter的一个例子
MyFormatterRegistrar类
package formatter;
import org.springframework.format.FormatterRegistrar;
import org.springframework.format.FormatterRegistry;
public class MyFormatterRegistrar implements FormatterRegistrar {
private String datePattern;
public MyFormatterRegistrar(String datePattern) {
this.datePattern = datePattern;
}
@Override
public void registerFormatters(FormatterRegistry registry) {
registry.addFormatter(new DateFormatter(datePattern));
// register more formatters here
}
}
有了Registrar,就不需要在Spring MVC配置文件中 注册任何Formatter了,只在Spring配置文件中注册 Registrar
springmvc-config配置
<?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 http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置自定义扫描的包 --> <context:component-scan base-package="controller"> </context:component-scan> <context:component-scan base-package="formatter" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 和 后缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 转换器 --> <mvc:annotation-driven conversion-service="conversionService" /> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="formatterRegistrars"> <set> <bean class="formatter.MyFormatterRegistrar"> <constructor-arg type="java.lang.String" value="MM-dd-yyyy" /> </bean> </set> </property> </bean> </beans>
四. 选择Converter,还是 Formatter
Converter是一般工具,可以将一种类型转换成另一 种类型。例如,将String转换成Date,或者将Long转换 成Date。Converter既可以用在Web层,也可以用在其他 层中
将String转换成Date,但它不能将Long转换成 Date。因此,Formatter适用于Web层。为此,在Spring MVC应用程序中,选择Formatter比选择Converter更合 适。