首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Struts2 接收前端 Date 類型參數失敗:後端用 String 接收再轉換

     編輯:程式設計疑難解答

問題現象

JSP 頁面提交表單,包含日期字段(如 <input type="date" name="birthDate">)。Action 中定義 private Date birthDate; 及對應 Getter/Setter,**後端接收到的 birthDate 為 null**,無法自動類型轉換。

根本原因

Struts2 默認類型轉換器 DateConverter 要求輸入字符串**嚴格匹配預設格式** (通常為 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)。前端提交的格式可能因瀏覽器、Locale、type="date" 實現差異而不匹配(如 MM/dd/yyyy、帶時區等),導致轉換拋異常被靜默吞噬,屬性最終為 null。

解決方案:後端接收 String 再手動解析 (最穩健)

public class UserAction extends ActionSupport {
    // 1. 定義 String 屬性接收原始輸入
    private String birthDateStr; 
    // 2. 真正的 Date 屬性供業務使用
    private Date birthDate; 
    
    // Getter/Setter
    public String getBirthDateStr() { return birthDateStr; }
    public void setBirthDateStr(String birthDateStr) { this.birthDateStr = birthDateStr; }
    public Date getBirthDate() { return birthDate; }
    public void setBirthDate(Date birthDate) { this.birthDate = birthDate; }
    
    @Override
    public String execute() {
        // 3. 在業務邏輯中手動解析,可控性最強
        if (birthDateStr != null && !birthDateStr.trim().isEmpty()) {
            try {
                // 嘗試多種常見格式
                SimpleDateFormat[] formats = {
                    new SimpleDateFormat("yyyy-MM-dd"),
                    new SimpleDateFormat("yyyy/MM/dd"),
                    new SimpleDateFormat("MM/dd/yyyy")
                };
                for (SimpleDateFormat fmt : formats) {
                    try {
                        fmt.setLenient(false);
                        this.birthDate = fmt.parse(birthDateStr.trim());
                        break; // 解析成功跳出
                    } catch (ParseException ignored) {}
                }
            } catch (Exception e) {
                addFieldError("birthDateStr", "日期格式無效,請使用 yyyy-MM-dd");
                return INPUT;
            }
        }
        // 繼續業務邏輯...
        return SUCCESS;
    }
}

替代方案:自定義類型轉換器 (全局生效)

1. 實現 TypeConverter

public class FlexibleDateConverter extends StrutsTypeConverter {
    private static final String[] PATTERNS = {
        "yyyy-MM-dd", "yyyy/MM/dd", "MM/dd/yyyy", "yyyy-MM-dd HH:mm:ss"
    };
    
    @Override
    public Object convertFromString(Map context, String[] values, Class toClass) {
        if (values == null || values.length == 0) return null;
        String val = values[0].trim();
        for (String pattern : PATTERNS) {
            try {
                SimpleDateFormat fmt = new SimpleDateFormat(pattern);
                fmt.setLenient(false);
                return fmt.parse(val);
            } catch (ParseException ignored) {}
        }
        throw new IllegalArgumentException("無法解析日期: " + val);
    }
    
    @Override
    public String convertToString(Map context, Object o) {
        if (o instanceof Date) {
            return new SimpleDateFormat("yyyy-MM-dd").format((Date)o);
        }
        return "";
    }
}

2. 註冊 (xwork-conversion.properties 或註解)

# xwork-conversion.properties (放在 src/main/resources)
java.util.Date=com.yourpkg.FlexibleDateConverter

或在 Action 字段上:@TypeConversion(converter = "com.yourpkg.FlexibleDateConverter")。

前端配合最佳實踐

  • 使用 <input type="date"> 瀏覽器原生日期選擇器,**提交格式固定為 yyyy-MM-dd (ISO 8601)**,最兼容 Struts2 默認轉換器。
  • 若需兼容舊瀏覽器,用 JS 日期插件 (如 laydate, flatpickr) 並**強制設置輸出格式為 yyyy-MM-dd**。
  • 避免依賴 type="text" 手動輸入,格式不可控。

總結

「最後的解決方案是在後台定義一個字符串,然後手動轉成日期」 是最直接、可控、不依賴框架默認行為的做法。若項目中日期字段極多,建議實現 全局自定義 TypeConverter 統一處理多格式解析,一次配置全項目受益。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved