SpringMVC DateTimeFormat和Converter衝突問題
阿新 • • 發佈:2019-01-04
專案老介面中日期引數是通過@DateTimeFormat接收並格式化的,而且多有種日期格式,為了統一管理,準備將新介面日期引數統一為時間戳。新增時間戳日期轉換類後,發現之前介面的@DateTimeFormat都失效了,為了相容老介面,只能檢視原始碼對有無@DateTimeFormat的日期型別分別怎樣處理。
結果發現,當引數解析需要型別轉換時,會先查詢轉換器,並檢查轉換器是否匹配,然後通過轉換器做型別轉換。
當沒有加入Converter<String, Date>時,帶有@DateTimeFormat註解的日期引數會得到DateTimeFormatAnnotationFormatterFactory作為轉換器工廠,實現型別轉換。沒有@DateTimeFormat註解的日期引數會得到ObjectToObjectConverter作為轉換器實現型別轉換。
當加入Converter<String, Date>後,所有的日期引數都會優先獲得這個轉換器,因此導致@DateTimeFormat註解失效。
在新增型別轉換工具時,會將新加入的Bean放在儲存連結串列的前面,保證比預設轉換器優先找到。相關程式碼如下
// GenericConversionService的內部類
private static class ConvertersForPair {
// 儲存型別轉換工具的List
private final LinkedList<GenericConverter> converters = new LinkedList< >();
public void add(GenericConverter converter) {
this.converters.addFirst(converter);
}
//其他屬性方法略
}
個人感覺,無法通過修改配置的的手段解決衝突問題,所以只能通過修改Converter<String, Date>類以相容之前的日期格式來解決問題了,最後貼出日期轉化工具。
/**
* 字串->日期轉換器
*
* @author ly
*/
public class StringToDateConverter implements Converter <String, Date> {
/**
* 日期正則表示式
*/
private static final String DATE_REGEX = "[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])";
/**
* 日期格式
*/
private static final String DATE_PATTERN = "yyyy-MM-dd";
/**
* 時間正則表示式
*/
private static final String TIME_REGEX = "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d";
/**
* 時間格式
*/
private static final String TIME_PATTERN = "HH:mm:ss";
/**
* 日期和時間正則表示式
*/
private static final String DATE_TIME_REGEX = DATE_REGEX + "\\s" + TIME_REGEX;
/**
* 日期和時間格式
*/
private static final String DATE_TIME_PATTERN = DATE_PATTERN + " " + TIME_PATTERN;
/**
* 13位時間戳正則表示式
*/
private static final String TIME_STAMP_REGEX = "1\\d{12}";
/**
* 年和月正則表示式
*/
private static final String YEAR_MONTH_REGEX = "[1-9]\\d{3}-(0[1-9]|1[0-2])";
/**
* 年和月格式
*/
private static final String YEAR_MONTH_PATTERN = "yyyy-MM";
@Override
public Date convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
if (source.matches(TIME_STAMP_REGEX)) {
return new Date(Long.valueOf(source));
}
DateFormat format;
if (source.matches(DATE_TIME_REGEX)) {
format = new SimpleDateFormat(DATE_TIME_PATTERN);
} else if (source.matches(DATE_REGEX)) {
format = new SimpleDateFormat(DATE_PATTERN);
} else if (source.matches(YEAR_MONTH_REGEX)) {
format = new SimpleDateFormat(YEAR_MONTH_PATTERN);
} else {
throw new IllegalArgumentException();
}
try {
return format.parse(source);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}