需求描述
用戶最後登錄時間 `lastLoginTime` (Date 類型),有效期 7 天。需判斷當前時間是否超過 `lastLoginTime + 7天`,超過則視為過期(自動登出/刪除)。前端使用 ExtJS。
核心邏輯:時間戳毫秒數比較
// 推薦:使用長整型毫秒數比較,避免 Date 格式化解析開銷與時區陷阱
long now = System.currentTimeMillis(); // 當前毫秒數
long lastLogin = user.getLastLoginTime().getTime(); // 最後登錄毫秒數
long expireTime = lastLogin + 7L * 24 * 60 * 60 * 1000; // 過期時間點 (毫秒)
if (now >= expireTime) {
// 用戶過期:執行登出、刪除、標記等業務邏輯
result.put("result", false);
result.put("message", "用戶過期!");
} else {
long remainingDays = (expireTime - now) / (24 * 60 * 60 * 1000);
// 可選:返回剩餘天數供前端提示
}
方案對比
| 方案 | 代碼片段 | 優點 | 缺點 |
| 毫秒數比較 (推薦) | `System.currentTimeMillis()` + `date.getTime()` | 性能最高、無時區歧義、無格式化開銷、邏輯最清晰 | 無 |
| Date.after/before | `new Date().after(expireDate)` | 面向對象、可讀性好 | 需先構造 expireDate 對象、內部仍轉毫秒數 |
| Calendar 加減 | `cal.add(Calendar.DAY, 7); now.after(cal.getTime())` | 支持複雜日曆運算 (如工作日) | API 繁瑣、mutable 易出錯 |
| Java 8 java.time (現代) | `Instant.now().isAfter(lastLogin.toInstant().plusSeconds(7*24*3600))` | 不可變、線程安全、功能豐富、標準化 | 需 Java 8+、舊項目遷移成本 |
| 字符串格式化比較 (反模式) | `SimpleDateFormat` 格式化後字符串比較 | 無 | 性能差、格式敏感、時區陷阱、邏輯錯誤高發 |
用戶原始代碼問題分析
SimpleDateFormat sdf = new SimpleDateFormat("03/08/2015 00:00:00 "); // 格式化模板寫死為具體日期!
String outlogin = sdf.format(new Date()); // 格式化當前時間為 "03/08/2015 ..."
if(................){ ... }
- **模板寫死**:`"03/08/2015 00:00:00 "` 不是模板,是固定字符串,`format` 會忽略模板字段直接輸出字面量。
- **字符串比較**:無法直接比較大小,需解析回 Date/Long。
- **時區風險**:`SimpleDateFormat` 默認使用 JVM 時區,服務器/客戶端時區不一致會導致判斷偏差。
ExtJS 前端配合
- 後端返回 JSON:`{ success: true, expired: false, remainingDays: 3 }` 或 `{ success: false, message: "用戶過期!" }`。
- 前端攔截器:`Ext.Ajax.on('requestcomplete', ...)` 或全局 `Ext.util.Observable` 監聽 `expired: true`,自動跳轉登錄頁、清理本地存儲。
- 心跳機制:前端定時輪詢 `/api/heartbeat`,後端檢查過期並返回狀態,實現「掉線即過期」。
最佳實踐總結
- **存儲統一用 UTC 毫秒數** (Long/BIGINT),DB 字段 `BIGINT` 或 `TIMESTAMP` (UTC)。
- **業務計算全程用 Long 毫秒數**,避免 Date/Calendar 可變性陷阱。
- **Java 8+ 項目強制遷移到 `java.time`** (`Instant`, `Duration`, `Period`, `ZonedDateTime`)。
- **前端不做時間計算**,只顯示後端返回的剩餘時間/過期狀態。
- **定時清理任務**:獨立排程任務 (Quartz/XXL-JOB) 批量掃描過期用戶執行刪除/歸檔,而非依賴用戶訪問觸發。
最佳回答給出偽代碼核心邏輯:`nowtime - lasttime` 比較毫秒差,轉換天數。雖用 `SimpleDateFormat` 解析 DB 時間略繞彎,但毫秒數比較思路正確。
- 上一篇文章: Win32 程序 RegisterClass 失敗排查:GetLastError 定位錯誤碼
- 下一篇文章: 解決 SQL Server Compact Edition (SQL CE) 桌面管理器連接資料庫錯誤的方法
Copyright ©
程式碼之家 All Rights Reserved