J2EE用监听器实现同一用户只能有一个在线
這里我們討論的是已登陸或?qū)⒁顷懙挠脩?#xff0c;游客不在討論的范圍之內(nèi)。這一點大家應(yīng)該很容易就能理解的吧。
??????????????
那么我們應(yīng)該怎樣去實現(xiàn)同一用戶只能有一個在線這樣的一個小功能呢?
有人可能就會這樣設(shè)想了:"這不是很簡單嗎?只要在數(shù)據(jù)庫中用一個字段來標記用戶的狀態(tài)就行了,比如如果用戶登陸了就將狀態(tài)設(shè)為1,退出了就將這個用戶的狀態(tài)設(shè)為0,OK,搞定。"
???????????????
但是,實際上是不是這樣呢?其實不全是。為什么這樣說呢?其實如果你的想法跟上面那樣或相似的話,應(yīng)該說是犯了一個比較嚴重的錯誤。我還是舉個例子來說明吧。現(xiàn)在絕大多數(shù)的網(wǎng)站中都有登陸和退出兩項功能吧?好了,上面的設(shè)想僅僅是針對這兩項功能來說使用。但是你有沒有想過?假如現(xiàn)在有一個用戶正常登陸上了,但是這回情況有點特殊了,這個用戶登陸上但是這個用戶就偏偏不點退出,然后就走了或者離開了或者忙別的事情去了,反正這個用戶登陸上就不管別的了,他就掛在那里。這種情況是允許發(fā)生了,而且也是比較常見的一種情況。那如果是這種情況,上面的那種設(shè)想你還認為是正確的嗎?那就不正確了!對session有過一點了解的人員應(yīng)該都知道,在java中session的默認的銷毀時間是大于或等于30分鐘,如果你對session的生命周期不做任何配置的話,按照上面的設(shè)想,那么只要用戶登陸上之后,這時該用戶的狀態(tài)設(shè)置為1,在大于30分鐘的時間內(nèi)如果該用戶沒有向服務(wù)器端發(fā)起任何請求的話,那么這個session就會被銷毀掉,注意了,這時session生命周期結(jié)束以后自動銷毀的,并不是用戶點退出按鈕來銷毀的,那這樣就不能觸發(fā)用戶退出事件,那這個用戶的狀態(tài)你就沒法改變了,也就是說,如果按照上面的設(shè)想,你想想,如果遇到這樣的情況,那這個用戶的狀態(tài)就一直都是1了,那這個用戶以后再想登陸就再也登陸不上了。很明顯,這樣是不對的。
???????????????
那應(yīng)該怎樣來解決這個問題呢?大家看到我這篇文章的標題就應(yīng)該知道了的吧。可以使用java的監(jiān)聽器來解決這個問題。在編程的開始你應(yīng)該有這樣一個了解:
????????????????
當用戶通過網(wǎng)絡(luò)來訪問一個網(wǎng)站的時候,如果是首次訪問,那么在這個網(wǎng)站的服務(wù)器端都會創(chuàng)建一個session來保存一些屬于這個用戶的信息。在創(chuàng)建session的時候其實是會觸發(fā)一個sessionCreated事件的,同樣的,當用戶正常退出或者是用戶登陸了不退出并當session生命周期結(jié)束的時候,就會觸發(fā)一個sessionDestroyed事件。這兩個事件我們可以通過HttpSessionListener監(jiān)聽器來監(jiān)聽到并可以把它捕捉。那這樣問題就好解決了。
???????????????
我話說的也有點多了,朋友們不要介意哈。好了,下面來看一下代碼
????????????????
注:為了演示簡單,我就不對用戶做封裝了,也不使用數(shù)據(jù)庫了,同樣的我也不添加任何的SSH框架支持了,我知道你們都懂的。不懂的可以給我留言。在這里我就直接用servlet來模擬了。我直接將用戶登陸后的信息保存到一個ServletContext對象中。順便我也簡單說一下ServletContext吧,怕有人對ServletContext不了解的。ServletContext對象是在你項目第一次啟動服務(wù)器的時候被創(chuàng)建的,這個對象是只被創(chuàng)建一次,是唯一的,你可以用ServletContextListener這個監(jiān)聽器來監(jiān)聽的到。
????????
??????????
login.jsp:
<%@ 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:
<%@ 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:
<%@ 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("您已經(jīng)登錄在線,不能重復登錄!");
}
</script>
</head>
<body onload="warn();">
您已經(jīng)登陸在線,不能重復登陸! <br>
<a href="/online/login.jsp">返回主頁</a>
</body>
</html>
????????
下面來看一下登陸的servlet
???
LoginServlet:
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 {
//在項目啟動第一次時創(chuàng)建,該項目只創(chuàng)建一次,唯一的
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){
//如果該用戶已經(jīng)登錄,請求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:
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設(shè)置成無效
request.getSession().invalidate();
response.sendRedirect("/online/login.jsp");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
?????????
最后就是監(jiān)聽器了,寫監(jiān)聽器類也是很簡單的,只要實現(xiàn)相應(yīng)的監(jiān)聽器接口并實現(xiàn)未實現(xiàn)的方法就行了。下面我寫一個SessionListener,它實現(xiàn)了HttpSessionListener接口:
package com.ljq.servlet;import java.util.ArrayList;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 當用戶通過網(wǎng)絡(luò)來訪問一個網(wǎng)站的時候,如果是首次訪問,那么在這個網(wǎng)站的服務(wù)器端都會創(chuàng)建一個session來保存一些屬于這個用戶的信息。
*
* 在創(chuàng)建session的時候其實是會觸發(fā)一個sessionCreated事件的,同樣的,當用戶正常退出或者是用戶登陸了不退出并當session生命周期結(jié)束的時候,
*
* 就會觸發(fā)一個sessionDestroyed事件。這兩個事件我們可以通過HttpSessionListener監(jiān)聽器來監(jiān)聽到并可以把它捕捉。
*
* @author Administrator
*
*/
public class SessionListener implements HttpSessionListener{
public void sessionCreated(HttpSessionEvent event) {
System.out.println("---Session被創(chuàng)建!---");
}
@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設(shè)置成無效
session.invalidate();
System.out.println("一個Session被銷毀了!");
}
}
???????
工作還沒結(jié)束呢,我還得配置一下web.xml文件,不然服務(wù)器是不會認識到這個監(jiān)聽器的:
<!-- 監(jiān)聽器注冊 --><listener>
<!-- 監(jiān)聽器類的路徑 -->
<listener-class>com.ljq.servlet.SessionListener</listener-class>
</listener>
?????
為了測試能及時看到效果,我再來配置一下session的存在時間,下面我將session的生命周期配置成一分鐘:
<session-config><session-timeout>1</session-timeout>
</session-config>
OK,完事了。這樣就能實現(xiàn)同一用戶只能有一個在線了
?
總結(jié)
以上是生活随笔為你收集整理的J2EE用监听器实现同一用户只能有一个在线的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win 7 系统激活工具
- 下一篇: Linux命令整理 - 文件搜索【4】