項目運行時突然拋出異常:
java.lang.NoSuchMethodException: com.ca.agent.model.mybatis.ApprovalInforCangra.setSubDate([Ljava.lang.String;)
異常發生在攔截器階段,Action 尚未進入。功能前期測試完全正常,排查半天無果,最終同事協助定位:IE 瀏覽器語言環境被改為英語,導致 Struts2 默認日期格式解析失敗。
yyyy-MM-dd(如 2023-10-01)。java.util.Date。Locale 選擇解析格式,英語環境下 SHORT 格式為 M/d/yy,無法匹配 yyyy-MM-dd。Struts2 內部按優先級嘗試多種 DateFormat:
private DateFormat[] getDateFormats(Locale locale) {
DateFormat[] dfs = {
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale),
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale),
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"), // RFC3339 硬編碼
DateFormat.getDateInstance(DateFormat.SHORT, locale), // 關鍵:英語下為 M/d/yy
DateFormat.getDateInstance(DateFormat.MEDIUM, locale),
DateFormat.getDateInstance(DateFormat.LONG, locale)
};
return dfs;
}
英語 Locale.US 下,DateFormat.getDateInstance(SHORT) 返回 M/d/yy,完全不匹配 yyyy-MM-dd。前六種格式均失敗,最終落回硬編碼的 RFC3339 格式(含 'T'),仍不匹配,拋出 ParseException,轉換失敗。
public class DateConverter extends DefaultTypeConverter {
private static final String[] PATTERNS = {"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM"};
@Override
public Object convertValue(Map context, Object value, Class toType) {
if (toType == Date.class && value instanceof String) {
String str = (String) value;
return DateUtils.parseDate(str, PATTERNS); // Commons Lang3
} else if (toType == String.class && value instanceof Date) {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value);
}
return null;
}
}
在 classpath 下創建 xwork-conversion.properties 註冊全局生效:
java.util.Date=com.yourpkg.DateConverter
ActionContext.getContext().setLocale(Locale.CHINA);
但需前端配合,且不利於用戶直接輸入。
yyyy-MM-dd、yyyy-MM-dd HH:mm:ss、時間戳毫秒數),兼容性最強。java.sql.Date 繞過轉換,破壞領域模型純粹性。參考資源:Struts2 類型轉換 Wiki、IE Locale 導致日期解析失敗案例