J2EE用监听器实现同一用户只能有一个在线
这里我们讨论的是已登陆或将要登陆的用户,游客不在讨论的范围之内。这一点大家应该很容易就能理解的吧。
那么我们应该怎样去实现同一用户只能有一个在线这样的一个小功能呢?
有人可能就会这样设想了:"这不是很简单吗?只要在数据库中用一个字段来标记用户的状态就行了,比如如果用户登陆了就将状态设为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这个监听器来监听的到。
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("您已经登录在线,不能重复登录!"); }</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,完事了。这样就能实现同一用户只能有一个在线了
J2EE用监听器实现同一用户只能有一个在线相关推荐
- linux创建sftp用户并指定访问目录,linux – 创建SFTP用户只能访问一个目录.
我更喜欢创建用户组sftp,并将该组中的用户限制在其主目录中. 首先,编辑你的/ etc / ssh / sshd_config文件并将其添加到底部. Match Group sftp ChrootD ...
- 远程服务器用户多开,服务器安全之修改远程桌面限制同一用户使用同一个会话。一个用户只开一个会话禁止多开。...
最近远程主机重装系统后,使用远程桌面出现一个问题:同一个用户先后登录远程系统,系统分配了不同会话.当系统分配不同会话时,导致你在一个远程桌面的操作都不见了.像是你运行的一些程序,虽然他们没有被系统关闭 ...
- Sqlserver中 登录用户只能看到自己拥有权限的库
Sqlserver中 登录用户只能看到自己拥有权限的库 转自:https://www.cnblogs.com/huangtailang/p/4209180.html SSMS设置:https://ww ...
- aix系统服务器限制ftp访问,AIX 限制ftp用户只能访问其主目录
aix 新建个普通用户test,想让此用户只能ftp到指定的目录下/backup,权限只读:不能进入到其他目录下.如何能实现呢? 1.创建并编辑ftpaccess.ctl #touch /etc/ft ...
- shiro 删除用户session_我的shiro之旅: 十二 shiro 踢出用户(同一用户只能一处登录)...
看了一下官网,没有找到关于如何控制同一用户只能一处登录的介绍,网上也没有找到相关的文章.可能有些人会记录用户的登录信息,然后达到踢出用户的效果.这里介绍一个更简单的方法. 如果我们跟shiro的源码, ...
- Sql Server设置用户只能查看并访问特定数据库
1.新建登录用户 以管理员身份登陆数据库(权限最高的身份如sa),点击安全性->登录名,右键新建登录名,输入登录名和密码,取消强制实施密码策略. 2.将服务器角色设置为public 注意:很重 ...
- 同一个PC只能运行一个应用实例(考虑多个用户会话情况)
原文:同一个PC只能运行一个应用实例(考虑多个用户会话情况) 1 class Program 2 { 3 private static Mutex m; 4 5 [STAThread] 6 stati ...
- php同个用户同时只能登陆一个, 后登陆者踢掉前登陆者
php同个用户同时只能登陆一个, 后登陆者踢掉前登陆者php同个用户同时只能登陆一个, 后登陆者踢掉前登陆者 通常用户登陆,如果没有特别的限定, 同一个用户可以同时登陆, 今天搞了一个东西限定一个用户 ...
- SQL Server 2008等登录用户只能看到自己的数据库设置办法
默认情况下登录用户除了看到自己拥有管理权限的数据库外.还可以看到其他数据库,在点击打开时会提示没有权限.如下设置可使该用户只能看到自己拥有管理权限的数据库,而看不到其他没有权限的数据库. (1)取消默 ...
最新文章
- JAVA显式锁,各种锁分类
- 独立成分分析ICA系列1:意义
- php dirtoarray,PHP Ds\Stack toArray()用法及代码示例
- JS相关知识总结(一)
- 为什么使用数据库从库
- 51单片机C51程序
- 提升安全性WindowsXP必禁的十大服务
- 跟随冒号畅游编程世界
- [转载] 【numpy】numpy.ones()函数
- 树梅派输入法黑块问题
- Linux系统中打开文件数量的查看方法
- Latex复杂三线图的处理
- CentOS6.7 i686上安装JDK7
- matlab gpa排名,GPA如何决定申请排名多少的大学?(附TOP100大学要求)
- 【面试突击算法第二天】剑指offer + Leetcode Hot100
- 利用OA系统进行档案管理原来这么简单?
- STM32中的IDR和ODR寄存器
- SSM毕设项目某企业危化品信息管理系统bf339(java+VUE+Mybatis+Maven+Mysql)
- OSI参考模型(七层模型)
- ERROR in xxx.js from UglifyJs