Session管理之超時設定和強制下線
關於Session,在Java Web開發中,為我們提供了很多方便,Session是由瀏覽器和伺服器之間維護的。好吧,閒話不多說,下面讓我們一步一步來實現它們。
(一)首先來說下Session超時時間設定的三種方式,這些相對來說比較簡單:
(1)在web.xml中設定session-config
<session-config>
<session-timeout>2</session-timeout>
</session-config>
即互動間隔時間最長為2分鐘(該處時間單位為分鐘),2分鐘後session.getAttribute()獲取的值為空。
(2)在Tomcat的/conf/web.xml中session-config,預設值為:30分鐘
<session-config>
<session-timeout>30</session-timeout></session-config>
同上,時間單位為分鐘。
(3)在Servlet中設定
HttpSession session = request.getSession();
session.setMaxInactiveInterval(60);
即在你的程式程式碼中手動設定(該處時間單位為秒)。
優先順序:Servlet中設定 >web.xml設定 > Tomcat/conf/web.xml設定
(二)同一使用者強制下線
大家都知道在目前很多的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();
最後,使用者登入驗證成功時需要呼叫一個方法來判斷是否強制下線:
publicstaticvoiduserLogin(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")@ResponseBodypublic 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秒判斷一次
}
functioncheckUserOnline(){ 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:
您的賬號已在另一處登入!
此時,重新整理第一個瀏覽器使用者登入介面,便會發現已經退出跳轉到登入頁了,大功告成!!!
公眾號推薦:
公眾號:VOA英語每日一聽
微訊號: voahk01
可長按掃碼關注,謝謝