SimpleDateFormat lst = new SimpleDateFormat("yyyy-MM-dd");
TransLogInfo transLogInfo = transLogInfoService.QueryTransLogInfo("intTxnDt");
String log = transLogInfo.getIntTxnDt(); // ❌ 可能拋 NPE
Date logTime = lst.parse(log);
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(logTime);
錯誤訊息:Error calling method through OGNL,實際為 transLogInfo 為 null 導致 getIntTxnDt() 拋 NPE。
QueryTransLogInfo 在查無資料時回傳 null,而非空物件。null 呼叫方法導致 NullPointerException,被 OGNL(Struts2/WebWork 表達式語言)包裝為上述錯誤。SimpleDateFormat lst = new SimpleDateFormat("yyyy-MM-dd");
TransLogInfo transLogInfo = transLogInfoService.QueryTransLogInfo("intTxnDt");
if (transLogInfo != null && transLogInfo.getIntTxnDt() != null) {
String log = transLogInfo.getIntTxnDt();
try {
Date logTime = lst.parse(log);
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(logTime);
// 取得當前時間比較
Date now = new Date();
if (logTime.before(now)) {
// 邏輯:logTime 早於現在
} else {
// 邏輯:logTime 晚於或等於現在
}
} catch (ParseException e) {
log.error("日期格式解析失敗: {}", log, e);
// 拋出業務異常或預設處理
}
} else {
log.warn("查無交易記錄或交易時間為空");
// 業務預設邏輯
}
強烈建議棄用 Date/Calendar/SimpleDateFormat,改用 java.time 套件:
// 假設資料庫欄位為 DATE 或 TIMESTAMP,MyBatis 直接映射為 LocalDate/LocalDateTime
LocalDate txnDate = transLogInfo.getIntTxnDtAsLocalDate(); // 映射方法視實際實作調整
if (txnDate != null) {
LocalDate today = LocalDate.now(ZoneId.systemDefault()); // 或 ZoneOffset.UTC
int cmp = txnDate.compareTo(today);
if (cmp < 0) { /* 過去 */ }
else if (cmp > 0) { /* 未來 */ }
else { /* 今天 */ }
}
SimpleDateFormat 非執行緒安全,易在高併發下產生錯誤解析。compareTo、isBefore、plusDays 等語意清晰。Date 隱含系統預設時區造成跨環境不一致。<resultMap id="transLogMap" type="TransLogInfo">
<result column="int_txn_dt" property="intTxnDtAsLocalDate" jdbcType="DATE" javaType="java.time.LocalDate"/>
</resultMap>
或使用 TypeHandler 統一處理 java.time 類型映射。
| 現象 | 原因 | 修正 |
|---|---|---|
| OGNL NPE | Service 回傳 null 直接呼叫 getter | 加 null 檢查或回傳 Optional |
| ParseException | 資料庫日期格式與 SimpleDateFormat pattern 不符 | 確認 pattern(yyyy-MM-dd vs yyyy/MM/dd vs timestamp) |
| 時區偏移 | Date/Calendar 使用 JVM 預設時區 | 改用 java.time 明確指定 ZoneId |
| 執行緒不安全 | 共用 SimpleDateFormat 實例 | 使用 ThreadLocal 或改用 DateTimeFormatter |
從資料庫取時間比較,核心要點:1. 防禦性檢查 null、2. 捕捉解析異常、3. 遷移至 java.time 套件。若專案仍在 Java 7,至少將 SimpleDateFormat 改為 ThreadLocal 單例或每次新建,並統一時區設定。