這裏咱們討論的是已登錄或將要登錄的用戶,遊客不在討論的範圍以內。這一點你們應該很容易就能理解的吧。
那麼咱們應該怎樣去實現同一用戶只能有一個在線這樣的一個小功能呢?
有人可能就會這樣設想了:"這不是很簡單嗎?只要在數據庫中用一個字段來標記用戶的狀態就好了,好比若是用戶登錄了就將狀態設爲1,退出了就將這個用戶的狀態設爲0,OK,搞定。"
可是,其實是不是這樣呢?其實不全是。爲何這樣說呢?其實若是你的想法跟上面那樣或類似的話,應該說是犯了一個比較嚴重的錯誤。我仍是舉個例子來講明吧。如今絕大多數的網站中都有登錄和退出兩項功能吧?好了,上面的設想僅僅是針對這兩項功能來講使用。可是你有沒有想過?假如如今有一個用戶正常登錄上了,可是這回狀況有點特殊了,這個用戶登錄上可是這個用戶就恰恰不點退出,而後就走了或者離開了或者忙別的事情去了,反正這個用戶登錄上就無論別的了,他就掛在那裏。這種狀況是容許發生了,並且也是比較常見的一種狀況。那若是是這種狀況,上面的那種設想你還認爲是正確的嗎?那就不正確了!對session有過一點了解的人員應該都知道,在java中session的默認的銷燬時間是大於或等於30分鐘,若是你對session的生命週期不作任何配置的話,按照上面的設想,那麼只要用戶登錄上以後,這時該用戶的狀態設置爲1,在大於30分鐘的時間內若是該用戶沒有向服務器端發起任何請求的話,那麼這個session就會被銷燬掉,注意了,這時session生命週期結束之後自動銷燬的,並非用戶點退出按鈕來銷燬的,那這樣就不能觸發用戶退出事件,那這個用戶的狀態你就無法改變了,也就是說,若是按照上面的設想,你想一想,若是遇到這樣的狀況,那這個用戶的狀態就一直都是1了,那這個用戶之後再想登錄就再也登錄不上了。很明顯,這樣是不對的。
那應該怎樣來解決這個問題呢?你們看到我這篇文章的標題就應該知道了的吧。可使用java的監聽器來解決這個問題。在編程的開始你應該有這樣一個瞭解:
當用戶經過網絡來訪問一個網站的時候,若是是首次訪問,那麼在這個網站的服務器端都會建立一個session來保存一些屬於這個用戶的信息。在建立session的時候實際上是會觸發一個sessionCreated事件的,一樣的,當用戶正常退出或者是用戶登錄了不退出並當session生命週期結束的時候,就會觸發一個sessionDestroyed事件。這兩個事件咱們能夠經過HttpSessionListener監聽器來監聽到並能夠把它捕捉。那這樣問題就好解決了。
我話說的也有點多了,朋友們不要介意哈。好了,下面來看一下代碼
注:爲了演示簡單,我就不對用戶作封裝了,也不使用數據庫了,一樣的我也不添加任何的SSH框架支持了,我知道大家都懂的。不懂的能夠給我留言。在這裏我就直接用servlet來模擬了。我直接將用戶登錄後的信息保存到一個ServletContext對象中。順便我也簡單說一下ServletContext吧,怕有人對ServletContext不瞭解的。ServletContext對象是在你項目第一次啓動服務器的時候被建立的,這個對象是隻被建立一次,是惟一的,你能夠用ServletContextListener這個監聽器來監聽的到。javascript
login.jsp:html
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用戶登陸</title> </head> <body> <form action="/online/servlet/LoginServlet" method="post"> <table> <tr> <td>用戶暱稱:</td> <td><input type="text" name="username"/></td> </tr> <tr> <td>用戶密碼:</td> <td><input type="password" name="pwd" size="20"/></td> </tr> <tr> <td> </td> <td><input type="submit" value=" 登錄 "/></td> </tr> </table> </form> </body> </html>
而後是:home.jsp:java
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用戶主頁</title> </head> <body> 用戶 ${user} 登錄成功!<BR/> <a href="/online/servlet/LogoutServlet">安全退出</a> </body> </html>
error.jsp:web
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>友情提示</title> <script type="text/javascript"> function warn(){ alert("您已經登陸在線,不能重複登陸!"); } </script> </head> <body onload="warn();"> 您已經登錄在線,不能重複登錄! <br> <a href="/online/login.jsp">返回主頁</a> </body> </html>
下面來看一下登錄的servlet
LoginServlet:數據庫
package com.ljq.servlet; import java.io.IOException; import java.util.ArrayList; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //在項目啓動第一次時建立,該項目只建立一次,惟一的 ServletContext context = this.getServletContext(); String url="/online/home.jsp"; String username=request.getParameter("username"); username=new String(username.getBytes("ISO-8859-1")); //獲取用戶列表,第一次獲取時候爲空 ArrayList<String> users=(ArrayList<String>)context.getAttribute("users"); //第一個用戶登陸時 if(users==null){ users = new ArrayList<String>(); users.add(username); context.setAttribute("users", users); //將第一個用戶的名字保存到ServletContext對象中 //非第一個用戶登陸 }else{ for(String user : users){ //若是該用戶已經登陸,請求error.jsp不讓其再登陸 if(username.equals(user)){ url = "/online/error.jsp"; break; } } //若是該用戶沒登陸,就將該用戶的名字保存到ServletContext對象中 users.add(username); } request.getSession().setAttribute("user", username); //保存一下該用戶信息以備後用 response.sendRedirect(url); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
接下來是用戶點擊安全退出須要的servlet:
LogoutServlet:編程
package com.ljq.servlet; import java.io.IOException; import java.util.ArrayList; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") public class LogoutServlet extends HttpServlet { @SuppressWarnings("unchecked") public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取用戶信息 String user = (String)request.getSession().getAttribute("user"); ArrayList<String> users = (ArrayList<String>)this.getServletContext().getAttribute("users"); for(String u:users){ //將這個用戶從ServletContext對象中移除 if(user.equals(u)){ users.remove(u); break; } } //將session設置成無效 request.getSession().invalidate(); response.sendRedirect("/online/login.jsp"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
最後就是監聽器了,寫監聽器類也是很簡單的,只要實現相應的監聽器接口並實現未實現的方法就好了。下面我寫一個SessionListener,它實現了HttpSessionListener接口:安全
package com.ljq.servlet; import java.util.ArrayList; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * 當用戶經過網絡來訪問一個網站的時候,若是是首次訪問,那麼在這個網站的服務器端都會建立一個session來保存一些屬於這個用戶的信息。 * * 在建立session的時候實際上是會觸發一個sessionCreated事件的,一樣的,當用戶正常退出或者是用戶登錄了不退出並當session生命週期結束的時候, * * 就會觸發一個sessionDestroyed事件。這兩個事件咱們能夠經過HttpSessionListener監聽器來監聽到並能夠把它捕捉。 * * @author Administrator * */ public class SessionListener implements HttpSessionListener{ public void sessionCreated(HttpSessionEvent event) { System.out.println("---Session被建立!---"); } @SuppressWarnings("unchecked") public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); String user = (String)session.getAttribute("user"); ArrayList<String> users = (ArrayList<String>)session.getServletContext().getAttribute("users"); for(String u:users){ //將這個用戶從ServletContext對象中移除 if(u.equals(user)){ users.remove(u); break; } } //將session設置成無效 session.invalidate(); System.out.println("一個Session被銷燬了!"); } }
工做還沒結束呢,我還得配置一下web.xml文件,否則服務器是不會認識到這個監聽器的:服務器
<!-- 監聽器註冊 --> <listener> <!-- 監聽器類的路徑 --> <listener-class>com.ljq.servlet.SessionListener</listener-class> </listener>
爲了測試能及時看到效果,我再來配置一下session的存在時間,下面我將session的生命週期配置成一分鐘:網絡
<session-config> <session-timeout>1</session-timeout> </session-config>
OK,完事了。這樣就能實現同一用戶只能有一個在線了 session
相關文件主要來自網絡和我的編程。支持轉載