为什么需要数据转换与格式化
在实际操作中,经常会遇到表单中的日期字符串与JavaBean中的日期类型的属性需要自动转换的情况,而Spring MVC框架默认不支持这个格式转换,即在Spring MVC中时间数据无法实现自动绑定,必须要手动配置自定义数据类型的绑定。
在进行手动配置数据转换之前,需要先了解数据绑定的流程。
概述: Spring会根据请求方法签名的不同,将请求中的信息以一定的方式转换并绑定到请求方法的入参中。其实在请求信息真正到达处理方法之前,Spring MVC还完成了许多工作,包括数据转换、数据格式化,以及数据校验等。
数据绑定具体流程图
-
Spring MVC将ServletRequest对象以及处理方法的入参对象实例传递给DataBinder。
-
DataBinder调用ConversionService组件进行数据转换、格式化的工作,并将ServletRequest中请求信息填充到入参对象中。
-
然后DataBinder再调用Validator组件对已经绑定了请求数据的入参对象进行数据合法性的验证,并最终生成数据绑定结果BindingResult对象。
解析:
(1)DataBinder:
数据绑定的核心组件,它在整个流程中起到核心调度的作用。
(2)ConversionService:
Spring类型转换体系的核心接口,可以利用org.springframework.context.support.ConversionServiceFactoryBean
在Spring的上下文定义一个 ConversionService 。Spring会自动识别出上下文中的 ConversionService ,在Bean属性配置和处理方法入参绑定时,使用它进行数据转换。所以在对于前台form表单中时间字符串到后台Date数据类型的转换问题,就可以通过 ConversionService 解决。
例:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean"/>
注:在Spring MVC中,<mvc:annotation-driven/>
标签是简化配置,默认情况下,它会创建并注册一个默认的 DefaultAnnotationHandlerMapping (处理器映射) 与 AnnotationMethodHandlerAdapter(处理器适配器), 并且该注解还会注册一个 ConversionService 实例FormattingConversionServiceFactoryBean,所以无需手动配置上面代码。
(3)BindingResult:
BindingResult包含了已完成数据绑定的入参对象和相应的校验错误对象,Spring MVC会抽取BindingResult中的入参对象以及校验错误对象,将他们赋给处理方法的相应入参。
数据转换的两种方式
1、编写自定义转换器
Spring在 org.springframework.core.convert.converter.Converter
包中定义了最简单的Converter接口,它仅包括一个接口方法convert(),如图
Converter的作用就是将一种类型转换成另一种类型的对象。例如,用户输入的日期可能有多种形式,如"1987/1/1"、“1987-1-1” 等,这些都表示同一个日期。若希望Spring在将输入的日期绑定到Date时,使用不同的日期格式,则需要编写一个Converter,才能将字符串转换成日期。具体实现:首先需要创建一个
org.springframework.core.convert.converter.Converter
接口的Java类,然后将该实现了Converter接口的自定义转换器注册到ConversionServiceFactoryBean即可。
实现步骤如下:
- 创建 StringtoDateConverter.java
package cn.smbms.tools;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/***
* 字符串转日期格式工具类
* @author 14062
*
*/
public class StringToDateConverter implements Converter<String, Date>{
private String datePattern; //日期格式
public StringToDateConverter(String datePattern){
System.out.println("StringToDateConverter convert:"+datePattern);
this.datePattern=datePattern;
}
/**
* 将字符串转为日期格式并返回
*/
@Override
public Date convert(String s) {
Date date=null;
try {
date=new SimpleDateFormat(datePattern).parse(s);
System.out.println("StringToDateConverter convert date:"+date);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
}
- 装配自定义的ConversionService(将该实现了Converter接口的自定义转换器注册到ConversionServiceFactoryBean)
<mvc:annotation-driven conversion-service="myConversionService">
<mvc:message-converters>
<!--省略配置-->
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="myConversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="cn.smbms.tools.StringToDateConverter">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd"/>
</bean>
</list>
</property>
</bean>
由于 <mvc:annotation-driven/>
标签会自动注册一个默认的 ConversionService ,现在由于我们需要注册一个自定义的 StringToDateConverter,因此需要显式定义一个 ConversionService 来覆盖 <mvc:annotation-driven/ >
中的默认实现,通过配置 <mvc:annotation-driven/>
标签的 conversion-service 属性来完成。装配完成之后,就可以在任何控制器的处理方法中使用该转换器了。
2、使用@InitBinder装配自定义编辑器
对于数据转换,还有一种更灵活的方式,就是通过自定义的编辑器去实现数据的转换与格式化处理。具体实现步骤如下:
- 创建BaseController.java,并标注@InitBinder注解
- 修改Controller文件继承BaseController.java
package cn.smbms.controller;
import java.sql.Date;
import java.text.SimpleDateFormat;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
public class BaseController {
/**
* 使用@InitBinder解决Spring MVC日期类型无法绑定的问题
* @param dataBinder
*/
@InitBinder
public void initBinder(WebDataBinder dataBinder){
System.out.println("initBinder====================");
dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
}
注: 标注了@InitBinder注解的方法会在控制器初始化时调用。在initBinder()方法体内,通过dataBinder的registerCustomEditor()方法注册一个自定义编辑器:
- 第一个参数表示编辑器为日期类型(Date.class)
- 第二个参数表示使用自定义的日期编辑器(CustomDateEditor),时间格式为yyyy-MM-dd,true表示该参数是否允许为空(时间格式参数)。