自定义MVC请求参数日期格式化器
在SpringMVC中,前端参数绑定到控制器方法参数是MVC自动完成的,但某些情景中,SpringMVC不能自动完成。例如,日期格式化是最常见的需要我们在使用SpringMVC时去自定义日期解析逻辑的场景(SpringMVC默认能处理前端提交的形如yyyy/MM/dd
格式的日期字符串,即如果前端传送的是2020/01/01
这个字符串,那默认情况下,这个参数能被正确绑定到控制器方法中Date类型的参数上)。
一、日期格式化工具类
要想自定义MVC的日期格式化逻辑,可以实现Formatter<T>接口。这个接口专门用于格式化操作,不仅限于日期格式化。下面格式化工具类只是用于实验!!!因为,SimpleDateFormat是线程不安全的,大概是因为其操作了线程共享数据,从而导致多个线程在使用下面这个类的时候可能会出现数据错乱的情况,即日期数据错误。
package com.example.ssm.util;
import org.springframework.format.Formatter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* @author MonteCar1o
* @date 2021/12/25 9:36
* @description 日期格式化工具
*/
public class DateFormat implements Formatter<Date> {
private final String[] PATTERNS = {"yyyy/MM/dd", "yyyy-MM-dd", "yyyy.MM.dd", "yyyy年MM月dd日"};
@Override
public Date parse(String text, Locale locale) {
Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat();
for (String pattern : PATTERNS) {
sdf.applyPattern(pattern);
try {
date = sdf.parse(text);
break;
} catch (ParseException ignored) {
}
}
if (date == null) {
throw new IllegalArgumentException("日期字符串解析失败! 请指定使用以下格式日期:\t【" + PATTERNS[0] + "】\t【" + PATTERNS[1] + "】\t【" + PATTERNS[2] + "】\t【" + PATTERNS[3] + "】");
}
return date;
}
@Override
public String print(Date object, Locale locale) {
return new SimpleDateFormat(PATTERNS[0]).format(object);
}
}
二、注册日期格式化工具类
注册的方式有很多,这里只给出基于XML的日期格式化配置方式,直接在SpringMVC的XML配置文件中添加一下内容:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="com.example.ssm.util.DateFormat"/>
</set>
</property>
</bean>
这也是Spring官方文中给出的一种配置方式,其中conversion-service="conversionService"
是屏蔽SpringMVC注册的默认格式化转换服务而采用下面自定义的id="conversionService"
。关于这个注解的注释说明如下:
The bean name of the ConversionService that is to be used for type conversion during field binding.
This attribute is not required, and only needs to be specified if custom converters need to be configured.
If not specified, a default FormattingConversionService is registered with converters to/from common value types.
>>>
大致意思就是,这个名为conversionService的组件在发生字段绑定的时候被用来进行类型转换。
它不是必须的,仅仅当需要自定义转换器的时候才需要配置这个属性;如果没有指定,那么一个默认的FormattingConversionService被注册并用于类型转换。
再来看看FormattingConversionServiceFactoryBean
这个类:
其中afterPropertiesSet()
方法继承自InitializingBean
,见名知意当组件初始化并设置属性后需要干什么:
@Override
public void afterPropertiesSet() {
this.conversionService = new DefaultFormattingConversionService(this.embeddedValueResolver, this.registerDefaultFormatters);
ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
registerFormatters(this.conversionService);
}
即,一旦为FormattingConversionServiceFactoryBean
设置formatters属性后,那么我们设置的东西会被自动注册,也就是说我们的格式化工具类自动添加到类型转换服务中。
三、测试
控制器方法
package com.example.ssm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
/**
* @author MonteCar1o
* @date 2021/12/23 20:34
* @description 日期格式化测试
*/
@Controller
public class DateController {
@PostMapping("/date")
@ResponseBody
public String handleDate(Date date) {
System.out.println("控制器接收到的日期:" + date);
return date.toString();
}
}
正常场景