在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-