JavaWeb實現(xiàn)同一帳號同一時間只能一個地點登陸(類似QQ登錄的功能)
JavaWeb實現(xiàn)同一帳號同一時間只能一個地點登陸(類似QQ登錄的功能)的實現(xiàn)思路如下所示:
一、該功能有什么作用
大家想想吧。反正總會有這樣的需求的。這年頭什么需求不會有。。呵呵。有時候也不一定是需求,很有可能為了安全也會這么做。例如考試系統(tǒng),在線聊天系統(tǒng),很有必要做成這樣的吧。
二、實現(xiàn)過程
a.問題分析
在系統(tǒng)中,我們一般都是把登錄信息綁定到session中,看來從這入手是可能找到解決辦法。說白了,也就是當(dāng)用戶登錄時,判斷一下這個用戶有沒有登錄,如果登錄了,就把以前的那個session清除掉就OK了。??此坪芎唵问遣??其實你細想你會發(fā)現(xiàn)有以下問題:如何得到之前這個用戶有沒有登錄過,也就是如何訪問到所有登錄的session信息呢?
b.具體實現(xiàn)
大家知道,在j2ee api好像是沒有具體的方法直接得到所有session信息的。但是我們可以通過配制監(jiān)聽器,監(jiān)控所有的session創(chuàng)建和消毀過程,以及可以監(jiān)控session中的屬性的創(chuàng)建,刪除和替換過程。
其實我們只要做以下處理即可:
在保存用戶登錄信息到session時,對應(yīng)的也就是session一個屬性的創(chuàng)建過程(attributeAdded),可以把當(dāng)前這個session記錄到一個ArrayList中。
其實在保存到list中時你要首先遍歷一下這個list中有沒有已經(jīng)存在該用戶的登錄信息。如果存在就消毀掉這個list中存在的session信息,并且從list中移除,不存在就把該session信息放到list中。
在session的登錄信息消毀時,直接把該sesseion從list中移除掉。
還有就是當(dāng)用戶登錄后沒有退出直接登錄這個時候是一個session屬性的替換過程。也要做處理判斷新的用戶是否已經(jīng)在除了當(dāng)前session的其它session中是否存在。存在則刪除。
具體代碼如下:
package com.weirhp; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class RecordSessionListener implements HttpSessionAttributeListener, HttpSessionListener { private static List<SessionAndUser> sessions; public static String loginFlag = "loginUser"; static { if (sessions == null) { sessions = Collections.synchronizedList(new ArrayList<SessionAndUser>()); } } public void attributeAdded(HttpSessionBindingEvent e) { HttpSession session = e.getSession(); System.out.println("-------------*start added*-----------------------"); String attrName = e.getName(); // 登錄 if (attrName.equals(loginFlag)) { User nowUser = (User) e.getValue(); User sUser = (User)session.getAttribute(loginFlag); // 遍歷所有session for (int i = sessions.size()-1; i >= 0; i--) { SessionAndUser tem = sessions.get(i); if (tem.getUserID().equals(nowUser.getName())) { tem.getSession().invalidate();//自動調(diào)用remove break; } } SessionAndUser sau = new SessionAndUser(); sau.setUserID(nowUser.getName()); sau.setSession(session); sau.setSid(session.getId()); sessions.add(sau); } } public void attributeRemoved(HttpSessionBindingEvent e) { HttpSession session = e.getSession(); System.out.println("-------------*start Removed*-----------------------"); String attrName = e.getName(); // 登錄 if (attrName.equals(loginFlag)) { User nowUser = (User) e.getValue(); // 遍歷所有session for (int i = sessions.size()-1; i >= 0; i--) { SessionAndUser tem = sessions.get(i); if (tem.getUserID().equals(nowUser.getName())) { sessions.remove(i); break; } } } } public void attributeReplaced(HttpSessionBindingEvent e) { HttpSession session = e.getSession(); System.out.println("-------------*start replace*-----------------------"); String attrName = e.getName(); int delS=-1; // 登錄 if (attrName.equals(loginFlag)) { // User nowUser = (User) e.getValue();//old value User nowUser = (User)session.getAttribute(loginFlag);//當(dāng)前session中的user // 遍歷所有session for (int i = sessions.size()-1; i >= 0; i--) { SessionAndUser tem = sessions.get(i); if (tem.getUserID().equals(nowUser.getName())&&!tem.getSid().equals(session.getId())) { System.out.println("Remove:invalidate 1!"); delS=i; }else if(tem.getSid().equals(session.getId())){ tem.setUserID(nowUser.getName()); } } if (delS!=-1) { sessions.get(delS).getSession().invalidate();//失效時自動調(diào)用了remove方法。也就會把它從sessions中移除了 } } } public void sessionCreated(HttpSessionEvent e) { } public void sessionDestroyed(HttpSessionEvent e) { } }
在web.xml中的配制
<listener> <display-name>recordSession</display-name> <listener-class>com.weirhp.RecordSessionListener</listener-class> </listener>
三、可能存在的問題
整個個程序可能有的點沒有想到??赡艽嬖谝恍゜ug,用于具體項目需謹慎,歡迎大家拍磚,也希望給點建議。我再改進。
四、后來的一些思考
如果兩臺機器使用同一帳號在同一時刻登錄系統(tǒng),是不是兩個帳號都可以登錄成功呢。。(還有就是這個session List很大時,在遍歷的時間段中兩臺機器使用同一帳號在同一時刻登錄系統(tǒng)也可能會成功登錄的)。很是糾結(jié)。。應(yīng)該怎么控制呢?
(解決辦法:經(jīng)測試Listener在系統(tǒng)中是一個單例,在它的方法上加上synchronize關(guān)鍵字就可以保證list的線程安全了。)
以上所述是小編給大家介紹的JavaWeb實現(xiàn)同一帳號同一時間只能一個地點登陸(類似QQ登錄的功能),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Java中easypoi導(dǎo)入excel文件列名相同的處理方案
這篇文章主要介紹了Java中easypoi導(dǎo)入excel文件列名相同的處理方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Java經(jīng)典設(shè)計模式之模板方法模式定義與用法示例
這篇文章主要介紹了Java經(jīng)典設(shè)計模式之模板方法模式,簡單說明了模板方法模式的原理、定義,并結(jié)合實例形式分析了java模板方法模式的具體使用方法,需要的朋友可以參考下2017-08-08攔截Druid數(shù)據(jù)源自動注入帳密解密實現(xiàn)詳解
這篇文章主要為大家介紹了攔截Druid數(shù)據(jù)源自動注入帳密解密實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11java開發(fā)RocketMQ生產(chǎn)者高可用示例詳解
這篇文章主要為大家介紹了java開發(fā)RocketMQ生產(chǎn)者高可用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08Spring?Data?JPA框架的核心概念與Repository接口詳解
Spring?Data?JPA是Spring基于JPA規(guī)范的基礎(chǔ)上封裝的?套?JPA?應(yīng)?框架,可使開發(fā)者?極簡的代碼即可實現(xiàn)對數(shù)據(jù)庫的訪問和操作,本篇我們來了解Spring?Data?JPA框架的核心概念與Repository接口2022-04-04Java基于二維數(shù)組實現(xiàn)的數(shù)獨問題示例
這篇文章主要介紹了Java基于二維數(shù)組實現(xiàn)的數(shù)獨問題,涉及java針對數(shù)組的遍歷、計算、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01