在web请求中,遇到日期类型(Date)一般情况下比较头疼,因为可能涉及到各种格式问题,比如“2019-03-07 17:10:21”、“2019-03-07 17:10”、“2019-03-07”,甚至还有1551949821、1551949821000等等各种问题。这些问题,仅仅靠文档说明,很难保证不出问题。
那怎么解决这种棘手问题呢?其他各种数据绑定方式就不讲了,今天主要讲一种结合Springboot特性的无入侵无感知解决方案~
在SpringBoot的WebMvc实现中,专门提供了下面接口用于解决各种格式问题
/**
* Add {@link Converter Converters} and {@link Formatter Formatters} in addition to the ones
* registered by default.
*/
default void addFormatters(FormatterRegistry registry) {
}
该方法默认是空的。该方法的作用是从注释上很容易就明白了,就是注册Converter和Formatter的,那我们只需要注册一个日期转换类型的Converter便可以解决问题了。
那我们先写一个日期转换Converter
public class StringDateConverter implements Converter<String, Date> {
private static Logger logger = LoggerFactory.getLogger(StringDateConverter.class);
private static final String TIME_PATTERN_REGEX = "^\\d{1,13}$";
private static ThreadLocal<SimpleDateFormat[]> dateFormatLocal = new ThreadLocal<SimpleDateFormat[]>() {
@Override
protected SimpleDateFormat[] initialValue() {
return new SimpleDateFormat[] {
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
new SimpleDateFormat("yyyy-MM-dd HH:mm"),
new SimpleDateFormat("yyyy-MM-dd HH"),
new SimpleDateFormat("yyyy-MM-dd")
};
}
};
@Override
public Date convert(final String source) {
if (source == null || source.trim().equals("")) {
return null;
}
Date result = null;
String _src = source.trim();
// 1,数字类型
if (_src.matches(TIME_PATTERN_REGEX)) {
try {
long lTime = Long.parseLong(_src);
if (_src.length() > 10) {
result = new Date(lTime);
} else {
result = new Date(1000L * lTime);
}
} catch (Exception e) {
result = null;
logger.warn("[" + source + "]无法转化为日期!");
}
return result;
}
// 2,日期类型
SimpleDateFormat[] dateFormats = dateFormatLocal.get();
for (SimpleDateFormat dateFormat : dateFormats) {
try {
dateFormat.setLenient(false);
return dateFormat.parse(source);
} catch (ParseException e) {
logger.warn("[" + source + "]无法转化为" + dateFormat.toPattern() + "格式的日期!");
}
}
return null;
}
}
该StringDateConverter转换器支持把“yyyy-MM-dd HH:mm:ss”、“yyyy-MM-dd HH:mm”、“yyyy-MM-dd HH”、“yyyy-MM-dd”格式的字符串和long类型的数字转化为日期类型,并且是线程安全的。
然后,我们把该转换器注册到系统中即可。这也有两种方案:
方法1,系统中的WebConfig文件继承WebMvcConfigurer并且重载addFormatters方法:
@Configuration
@Import({ WebMvcAutoConfiguration.class })
@ComponentScan(
value = "com.beyonds.phoenix.shine.web",
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)
})
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringDateConverter());
}
}
方法2,直接把StringDateConverter注册成bean即可!
@Configuration
@Import({ WebMvcAutoConfiguration.class })
@ComponentScan(
value = "com.beyonds.phoenix.shine.web",
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)
})
public class WebMvcConfiguration {
/**
* 自定义输入的日期格式
* 覆盖spring.mvc.date-format
* @return 日期格式转换器
*/
@Bean
public StringDateConverter dateConverter() {
return new StringDateConverter();
}
}
为什么方法2也能生效呢,这就是SpringBoot内部自动机制实现了~
其实,在WebMvcAutoConfiguration内部实现中,有如下代码
@Override
public void addFormatters(FormatterRegistry registry) {
for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
registry.addConverter(converter);
}
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
registry.addConverter(converter);
}
for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
registry.addFormatter(formatter);
}
}
其作用很清楚,就是自动扫描并注册Converter、GenericConverter和Formatter到web处理器中~
-End-
网友评论