那么我們應該怎樣去實現同一用戶只能有一個在線這樣的一個小功能呢?
有人可能就會這樣設想了:"這不是很簡單嗎?只要在數據庫中用一個字段來標記用戶的狀態就行了,比如如果用戶登陸了就將狀態設為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這個監聽器來監聽的到。
下面來看實現吧:
我先做jsp吧,這里我需要三個jsp頁面:一個登陸login.jsp,一個首頁home.jsp,一個錯誤提示error.jsp。我盡量將jsp寫的簡單些,下面來開代碼,我就不多解釋了,一看就懂的
login.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用戶登錄</title>
</head>
<body>
[align=center]<br/><br/>
<form action="/SingleOnline/servlet/LoginServlet" method="post">
<table>
<tr>
<td>用戶昵稱:</td>
<td><input type="text" name="username" /></td>
</tr>
<tr>
<td>用戶密碼:</td>
<td><input type="password" name="userpssw" size="21" /></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value=" 登陸 " /></td>
</tr>
</table>
</form>
[/align]
</body>
</html>
home.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用戶主頁</title>
</head>
<body>
<!-- ${user}是EL表達式,如果用戶登陸成功就將用戶名字顯示出來 -->
用戶 ${user} 登陸成功!<BR/>
[url=/SingleOnline/servlet/LogoutServlet]安全退出[/url]
</body>
</html>
error.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>error page</title>
<script type="text/javascript">
function warn(){
alert('您已經登陸在線,不能重復登陸!');
}
</script>
</head>
<body onload="warn()">
您已經登陸在線,不能重復登陸! <br>
[url=/SingleOnline/home.jsp]返回主頁[/url]
</body>
</html>
下面來看一下登陸的servlet
LoginServlet:
package com.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;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginServlet() {
super();
}
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
doPost(request, response);
}
@SuppressWarnings("unchecked")
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
String uname = request.getParameter("username");
@SuppressWarnings("unused")
String upssw = request.getParameter("userpssw");
String url = "/SingleOnline/home.jsp";
try {
uname = new String(uname.getBytes("ISO-8859-1"));
} catch (Exception e) {e.printStackTrace();}
ServletContext context = this.getServletContext(); //獲取ServletContext
ArrayList<String> users = (ArrayList<String>)context.getAttribute("users"); //獲取用戶列表,第一次獲取時候為空
if(users == null){ //第一個用戶登錄時候:
users = new ArrayList<String>();
users.add(uname);
context.setAttribute("users", users); //將第一個用戶的名字保存到ServletContext對象中
}else{ //非第一個用戶登錄:
for(int i=0;i<users.size();i++){
String username = (String)users.get(i);
聰明女人與笨女人~! if(username.equals(uname)){ //如果該用戶已經登錄,請求error.jsp不讓其再登錄
url = "/SingleOnline/error.jsp";
break;
}
}
users.add(uname); //如果該用戶沒經登錄,就將該用戶的名字保存到ServletContext對象中
}
request.getSession().setAttribute("user", uname); //保存一下該用戶信息以備后用
response.sendRedirect(url);
}
}
接下來是用戶點擊安全退出需要的servlet:
LogoutServlet:
package com.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;
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LogoutServlet() {
super();
}
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
doPost(request, response);
}
@SuppressWarnings("unchecked")
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
String user = (String)request.getSession().getAttribute("user"); //獲取用戶信息
ArrayList<String> users = (ArrayList<String>)this.getServletContext().getAttribute("users"); // 獲取用戶列表
for(int i=0;i<users.size();i++){
String username = (String)users.get(i);
if(username.equals(user)){
users.remove(i); //將這個用戶從ServletContext對象中移除
break;
}
}
request.getSession().invalidate(); //將session設置成無效
response.sendRedirect("/SingleOnline/login.jsp");
}
}
最后就是監聽器了,寫監聽器類也是很簡單的,只要實現相應的監聽器接口并實現未實現的方法就行了。下面我寫一個SessionListener,它實現了HttpSessionListener接口:
package com.listener;
import java.util.ArrayList;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class SessionListener implements HttpSessionListener {
//session創建時,該方法被調用
//為了給朋友們看的清楚一些,我在兩個方法中都打印了一下信息
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("Session被創建!");
}
//session銷毀時候被調用(1.用戶安全退出;2.session生命周期結束)
@SuppressWarnings("unchecked")
public void sessionDestroyed(HttpSessionEvent arg0) {
HttpSession session = arg0.getSession(); //獲取session
String user = (String)session.getAttribute("user"); //獲取用戶信息
ArrayList<String> users = (ArrayList<String>)session.getServletContext().getAttribute("users"); //獲取用戶列表
for(int i=0;i<users.size();i++){
String username = (String)users.get(i);
if(username.equals(user)){
users.remove(i); //將這個用戶從ServletContext對象中移除
break;
}
}
session.invalidate(); //將session設置成無效
System.out.println("一個Session被銷毀了!");
}
}
posted on 2011-11-01 15:14
墻頭草 閱讀(603)
評論(0) 編輯 收藏