index.jsp → 重定向 /login/forwardLogin → LoginController.forwardLogin() 返回 login.jsp。/login/userLogin → userLogin() 調用 UserService.userLogin()。ProcResult(統一碼/消息/附加數據),Controller 根據碼決定重定向或轉發。// 統一返回封裝
class ProcResult implements Serializable {
int resCode; // 業務碼:LOGIN_SUCCESS, LOGIN_MULTI_LOGIN, WRONG_PWD...
String resMsg; // 提示信息
Map<String, Object> extra; // 附加數據(如攜帶 User 對象)
}
// 用戶實體(關鍵字段)
class User {
int userId;
String loginName, password;
int multiLogin; // 1/999 允許多點,0 禁止
int authLevel; // 1超管 2機構管 3部門管 4普通
Date duration; // 服務到期時間
int type; // 用戶類型
}
LoginAccount:多點登錄狀態中樞class LoginAccount {
private static Map<String, Map<String, Object>> accountInfo = new HashMap<>();
private static LoginAccount instance;
private LoginAccount() {}
public static LoginAccount getInstance() { // 雙檢鎖單例
if (instance == null) synchronized (LoginAccount.class) {
if (instance == null) instance = new LoginAccount();
}
return instance;
}
public void addLogin(String userId, Map<String, Object> info) { accountInfo.put(userId, info); }
public boolean checkLogin(String userId) { return accountInfo.containsKey(userId); }
public void removeLogin(String userId) { accountInfo.remove(userId); }
}
userId,Value = 登錄上下文(可擴展存 Token、IP、時間)。UserService.userLogin() 核心邏輯public ProcResult userLogin(HttpServletRequest request, String account, String pwd) {
User user = userDao.getLoginUserInfo(account); // SQL: login_name/mobile/email 三路查詢
if (user == null) return ProcResult.buildResult(LOGIN_WRONG_USER, "用戶不存在");
if (!user.getPassword().trim().equals(pwd))
return ProcResult.buildResult(LOGIN_WRONG_PWD, "密碼錯誤");
LoginAccount la = LoginAccount.getInstance();
boolean already = la.checkLogin(String.valueOf(user.getUserId()));
int multi = user.getMultiLogin();
List<Org> orgs = orgDao.getUserOrgs(user.getUserId());
if (already) {
if (multi == 1 || multi == 999) { // 允許多點
initLoginUserInfo(user, orgs, request);
return ProcResult.buildResult(LOGIN_SUCCESS, "登錄成功");
}
return ProcResult.buildResult(LOGIN_MULTI_LOGIN, "該賬號已在別處登錄");
}
// 首次登錄
if (user.getDuration() != null && user.getDuration().before(new Date()))
return ProcResult.buildResult(LOGIN_OUT_DURATION, "服務已到期");
initLoginUserInfo(user, orgs, request);
return ProcResult.buildResult(LOGIN_SUCCESS, "登錄成功");
}
BaseService.initLoginUserInfo():Session 與權限初始化orgs 判斷權限等級:無組織→4;超管/機構管→1/2;部門管→3。defaultOrgId,否則個人空間(type=0)。USER、ORG、USER_ORGS。LoginAccount(代碼中被註釋,實際生產需開啟)。該設計清晰分離 Controller/Service/Dao,ProcResult 統一錯誤碼,LoginAccount 單例管理多點狀態,initLoginUserInfo 集中處理 Session 與權限,是典型 SSM 登錄模塊的優秀參考。