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