一、問題引導
在Web開發中,實現一個賬號只能在一處登陸有兩種形式:1.當某個賬號在某處登陸后,如果再在其他處登陸,將前一個賬號擠掉;2.當某個賬號登陸后,此賬號在其他設備登陸提示已經登陸,無法登陸。 正常的應用邏輯第一種應用較為廣泛,因此此篇文章討論一下第一種邏輯在spring mvc開發中一種較為簡單的實現方式。
然而在沒有長連接如WebSocket或者異步請求輪詢的情況下,我們之前登陸的賬號只能在下一次請求(同步或異步)才能獲取被擠掉的狀態(如頁面跳轉)。
二、實現步驟
1.建立一個靜態Map,用來存放賬號和sessionID的對應關系
2.在登陸時,校驗Map中是否已存在此賬號,如果不存在說明是第一次登陸,將賬號和sessionID的對應關系存放到靜態Map中;如果Map中存在此賬號,并且sessionID和本次請求的sessionID不一致,將Map中的sessionID替換掉,因此之前登陸的賬戶在發送下一次非登錄和校驗的請求會被攔截。
3.創建攔截器,攔截除登陸和校驗url以外的所有請求。判斷請求的sessionID和靜態Map中此賬戶對應的sessionID是否一致。如果不一致,跳轉到登陸頁面。
三、實現代碼
1.創建一個內存數據類,用于存放靜態的數據,并初始化:
1
2
3
4
5
6
7
8
9
10
11
|
public class MemoryData { private static Map<String, String> sessionIDMap = new HashMap<String,String>(); public static Map<String, String> getSessionIDMap() { return sessionIDMap; } public static void setSessionIDMap(Map<String, String> sessionIDMap) { MemoryData.sessionIDMap = sessionIDMap; } } |
2.創建Controller,實現校驗登陸用戶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
@Controller public class AdminController extends BaseController{ @Autowired public AdminService adminService; /** * 校驗登陸管理員 * @param request * @param response * @throws IOException */ @RequestMapping (value= "/checkadmin" ) public void checkUserInfo(HttpServletRequest request,HttpServletResponse response) throws IOException{ //1在數據庫查找用戶 AdminBean admin = adminService.queryUserInfo(usernameS); //2將admin存放到Session中 request.getSession().setAttribute( "admin" , admin); //3在sessionIDMap中存放此用戶sessionID String sessionID = request.getRequestedSessionId(); String user = admin.getUsername(); if (!MemoryData.getSessionIDMap().containsKey(user)) { //不存在,首次登陸,放入Map MemoryData.getSessionIDMap().put(user, sessionID); } else if (MemoryData.getSessionIDMap().containsKey(user)&&!StringUtils.equals(sessionID, MemoryData.getSessionIDMap().get(user))){ MemoryData.getSessionIDMap().remove(user); MemoryData.getSessionIDMap().put(user, sessionID); } } } |
3.創建攔截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
public class SingleUserInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object arg2, Exception arg3) throws Exception { // TODO Auto-generated method stub } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView arg3) throws Exception { // TODO Auto-generated method stub } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception { String url = request.getRequestURI(); //如果攔截到的是登錄的頁面的話放行 if (url.indexOf( "login.do" )>= 0 ||url.indexOf( "checkadmin.do" )>= 0 ){ return true ; } //如果是其他請求地址,進行攔截 AdminBean admin = (AdminBean) request.getSession().getAttribute( "admin" ); if (admin!= null ){ String sessionid = MemoryData.getSessionIDMap().get(admin.getUsername()); //如果用戶名存在放心(即登錄放行) if (sessionid.equals(request.getSession().getId())){ return true ; } else { //如果請求的sessionID和此賬號Map中存放的sessionID不一致,跳轉到登陸頁 //判斷如果是異步請求,設置響應頭 sessionstatus為timeout,自動跳轉,否則重定向 if (request.getHeader( "x-requested-with" )!= null && request.getHeader( "x-requested-with" ).equalsIgnoreCase( "XMLHttpRequest" )){ response.setHeader( "sessionstatus" , "timeout" ); return false ; } else { String indexurl=request.getContextPath()+ "/login.do" ; response.sendRedirect(indexurl); return false ; } } } //如果session中沒有admin,跳轉到登陸頁 request.getRequestDispatcher(request.getContextPath()+ "/index.do" ).forward(request, response); return false ; } } |
4.在springmvc.xml配置文件中添加攔截器
1
2
3
4
5
6
7
|
<!--配置攔截器, 多個攔截器,順序執行 --> < mvc:interceptors > < mvc:interceptor > < mvc:mapping path = "/**" /> < bean class = "com.jiefupay.newplat.controller.SingleUserInterceptor" /> </ mvc:interceptor > </ mvc:interceptors > |
四、后續
此種方式實現一個賬號只能在一處登陸是一種較簡單的方法,當然也可以通過移除session的方式實現。本文皆由本人親測實現,如有錯誤,歡迎指正。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。