關於Session,在Java Web開發中,爲咱們提供了不少方便,Session是由瀏覽器和服務器之間維護的。好吧,閒話很少說,下面讓咱們一步一步來實現它們。javascript
(一)首先來講下Session超時時間設置的三種方式,這些相對來講比較簡單:前端
(1)在web.xml中設置session-configjava
<session-config> <session-timeout>2</session-timeout> </session-config>
即交互間隔時間最長爲2分鐘(該處時間單位爲分鐘),2分鐘後session.getAttribute()獲取的值爲空。web
(2)在Tomcat的/conf/web.xml中session-config,默認值爲:30分鐘ajax
<session-config> <session-timeout>30</session-timeout> </session-config>
同上,時間單位爲分鐘。瀏覽器
(3)在Servlet中設置服務器
HttpSession session = request.getSession(); session.setMaxInactiveInterval(60);
即在你的程序代碼中手動設置(該處時間單位爲秒)。session
優先級:Servlet中設置 >web.xml設置 > Tomcat/conf/web.xml設置app
(二)同一用戶強制下線jsp
你們都知道在目前不少的web項目中,大多數狀況下都是可讓同一個用戶帳號在不一樣的登陸入口登陸的,但這樣其實就顯得不是很嚴謹了,畢竟信息修改等操做對於信息是否能徹底即時同步仍是個未知之數。因此,接下來,我要作的只是對於不一樣瀏覽器的同一個用戶帳號的強制下線處理,對於同一個瀏覽器暫不作考慮,先來看下面這張圖。大概的瞭解一下:
從上面能夠看出:同一個瀏覽器對於不一樣的帳號,登陸時會產生相同的sessionId,這也就致使了用戶之間信息的覆蓋;不一樣瀏覽器對於不一樣的帳號登陸時,登陸時會產生不一樣的sessionId,這也就給了咱們可操做的空間了,正是要利用這一點來進行判斷和相應處理。
(1)添加監聽器
爲了方便這裏使用Session監控的方式,建立SessionListener,以下:
public class SessionListener implements HttpSessionBindingListener{ @Override public void valueBound(HttpSessionBindingEvent event){ // TODO Auto-generated method stub } @Override public void valueUnbound(HttpSessionBindingEvent event){ // TODO Auto-generated method stub } }
這裏HttpSessionBindingListener和HttpSessionListener效果同樣,你們能夠任選其一。重載兩個方法:session的建立和銷燬。
固然,在web.xml中添加相應配置是必不可少的:
<listener> <listener-class>com.yoki.util.SessionListener</listener-class> </listener>
因爲sessionId和userId須要存儲,方便後面的判斷,咱們在上面的類中添加兩個Map,以下:
//保存username和session的映射 public static HashMap<String,Session> MAP1 = new HashMap<String,Session>(); //保存sessionID和username的映射 public static HashMap MAP2 = new HashMap();
最後,用戶登陸驗證成功時須要調用一個方法來判斷是否強制下線:
public static void userLogin(Session session,String sUserName){ //已登陸 if(MAP2.containsValue(sUserName)){ Session l_session = MAP1.get(sUserName); //不一樣瀏覽器,同一用戶(強制下線前一個) if(l_session != null && l_session.getId() != session.getId()){ MAP1.remove(sUserName); MAP2.remove(l_session.getId()); l_session.setAttribute("msg", "您的帳號已在另外一處登陸!"); MAP2.put(session.getId(), sUserName); MAP1.put(sUserName, session); } //同一瀏覽器,同一用戶(不作任何變更) }else{ //未登陸 if(MAP2.containsKey(session.getId())){ //同一瀏覽器,不一樣用戶(不作任何變更) }else{ //不一樣瀏覽器,不一樣用戶(正常添加) MAP2.put(session.getId(), sUserName); MAP1.put(sUserName, session); } } }
解釋一下:這裏使用username和userId效果同樣,看大家怎麼方便怎麼用了,方法中的邏輯是根據上面的圖來編寫的,首先判斷用戶是否登陸了,由於MAP中保存了相關的session關聯信息,因此能夠經過這個來判斷;因爲此處只對不一樣瀏覽器相同用戶進行處理,因此直接判斷是不是同一個瀏覽器。方法的參數session是用戶在當前瀏覽器登陸時的信息,咱們能夠從MAP中獲得以前保存過的相同用戶的session信息,與之進行比較,裏面的邏輯是:移除MAP中保存的以前的用戶信息(對應的session此時未銷燬),並給其session添加一個msg信息(後面用到,往下看),再添加新的用戶信息。
上面的方法調用放在登陸驗證成功後,各自項目不一樣,但登陸驗證的類基本差很少:
SessionListener.userLogin(session, USERNAME);
(2)添加前端頁面調用的方法
在登陸驗證的類中添加以下方法:
/* * 判斷用戶是否重複登陸 */ @RequestMapping(value="/checkUserOnline") @ResponseBody public void checkUserOnline(HttpServletRequest request,HttpServletResponse response) throws IOException{ HttpSession session=request.getSession(); PrintWriter out = response.getWriter(); String msg = ""; if(session.getAttribute("msg") != null){ msg = session.getAttribute("msg").toString(); System.out.println(msg); } out.print(session.getAttribute("msg")); }
方法中獲取以前添加到session中的msg,用來判斷是否強制下線,繼續。
(3)前端頁面循環調用
選擇一個頁面,最好是全部頁面都用到的,好比我用的index.jsp,以下:
<script type="text/javascript"> $(document).ready(function(){ setInterval("checkUserOnline()",5000); //每隔5秒判斷一次 } function checkUserOnline(){ var msg = ""; $.ajax({ type : "POST", url : "checkUserOnline", data : {}, async: false, success : function(data){ msg = data; } }); if (msg == 'null' || msg == '' || msg == 'undefined'){ return; }else{ //調用你的註銷用戶方法 var url="<%=path%>/logout.do"; $.get(url,function(data){}); } } </script>
js中調用setInterval方法,設置調用的方法和間隔時間,方法裏經過ajax調用上面添加的類並返回msg,經過msg來判斷是否調用註銷方法(路徑啥的本身注意,能調用到就ok)。
(4)註銷
通常web項目登陸進去後都會有個退出按鈕,點擊即返回到登陸頁,此時在裏面添加一行代碼,防止錯誤,可能會出現從新登陸報session已被銷燬的錯誤提示,但第二次便會成功,這裏即是爲了消除該錯誤:
SessionListener.MAP2.remove(session.getId());
好了,基本的設置完成了,啓動項目,打開兩個不一樣的瀏覽器,先登陸一個用戶,成功後,在另外一個瀏覽器中登陸相同的用戶,登陸成功後,會在控制檯上打印出msg:
您的帳號已在另外一處登陸!
此時,刷新第一個瀏覽器用戶登陸界面,便會發現已經退出跳轉到登陸頁了,大功告成!!!