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 >          您已经登陆在线,不能重复登陆! <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,完事了。这样就能实现同一用户只能有一个在线了

时间: 2024-10-16 19:43:54

J2EE用监听器实现同一用户只能有一个在线的相关文章

怎么取消 Windows Server 2012 r2 RDP 限制每个用户只能进行一个会话(转)

在 Windows Server 2008 / 2008 R2 上,如果希望多个远程用户使用同一个账号同时访问服务器的 Remote Desktop(RDP),只需通过管理工具-远程桌面下的“远程桌面会话主机配置”进行设置即可.或是通过命令:在运行里输入“tsconfig“ 就能看到如下提示:将允许每个用户同时进行一个会话 设置为“否” 即可. 但是在 Windows Server 2012 下会发现系统默认并未提供这个配置工具,(可以手工通过添加角色和功能进行添加).所以如果要取消 Windo

关于同一个用户只能有一个账号登陆的方法

此种情况分两种办法,第一种是后面的踢掉前面的,另外一个是后面的不能登陆.前面一种很好实现,对于后面一种要稍微复杂些.

sqlserver 创建用户只能访问指定视图

use crm --当前数据库创建角色 exec sp_addrole 'rapp' --分配视图权限 GRANT SELECT  ON veiw TO [角色] --指定视图列表 GRANT SELECT ON  v_city TO rapp GRANT SELECT ON  v_lp TO rapp GRANT SELECT ON  v_qy TO rapp go --添加只允许访问指定视图的用户: exec sp_addlogin '登录名','密码','默认数据库名' exec sp_a

SQL Server 2008等登录用户只能看到自己的数据库设置办法

默认情况下登录用户除了看到自己拥有管理权限的数据库外.还可以看到其他数据库,在点击打开时会提示没有权限.如下设置可使该用户只能看到自己拥有管理权限的数据库,而看不到其他没有权限的数据库. (1)取消默认可查看任何数据库 DENY VIEW any DATABASE TO PUBLIC;  -- 没有进行权限设置,所有默认的登录用户不能查看任何数据库 (2)赋予自己拥有管理权限的数据库的查看权限 ALTER AUTHORIZATION ON DATABASE::DBName TO DBUser;

我的shiro之旅: 十二 shiro 踢出用户(同一用户只能一处登录)

我的shiro之旅: 十二 shiro 踢出用户(同一用户只能一处登录) 2014年09月05日 ⁄ 综合 ⁄ 共 4677字 ⁄ 字号 小 中 大 ⁄ 评论关闭 看了一下官网,没有找到关于如何控制同一用户只能一处登录的介绍,网上也没有找到相关的文章.可能有些人会记录用户的登录信息,然后达到踢出用户的效果.这里介绍一个更简单的方法. 如果我们跟shiro的源码,我们可以看到.当用户登录成功 后,shiro会把用户名放到session的attribute中,key为 DefaultSubjectC

同一个PC只能运行一个应用实例(考虑多个用户会话情况)

原文:同一个PC只能运行一个应用实例(考虑多个用户会话情况) 1 class Program 2 { 3 private static Mutex m; 4 5 [STAThread] 6 static void Main() 7 { 8 bool createNew = false; 9 10 /* 11 * 在运行终端服务的服务器上,已命名的系统 mutex 可以具有两级可见性. 12 * 如果名称以前缀“Global\”开头,则 mutex 在所有终端服务器会话中均为可见. 13 * 如果

如何给VSFTP增加用户,只能访问指定目录

1 增加组 groupadd ftpgroup 2 修改/etc/vsftpd/vsftpd.conf 将底下三行 #chroot_list_enable=YES # (default follows) #chroot_list_file=/etc/vsftpd.chroot_list 改为 chroot_list_enable=YES # (default follows) chroot_list_file=/etc/vsftpd/chroot_list 3 增加用户 useradd -g f

Sqlserver中 登录用户只能看到自己拥有权限的库

执行之前新建用户时不要赋予任何权限 USE master GO --将所有数据库的查看权限给Public角色,每个登录用户只能查看指定的数据库 --此语句会导致服务器上所有的用户在没有设置数据库权限的情况下不会显示任何数据库,有可能会影响正常使用 DENY VIEW any DATABASE TO PUBLIC; --将数据库Test的所有权给TestUser用户 --TestUser用户可以查看并访问Test数据库 ALTER AUTHORIZATION ON DATABASE::Test T

oracle 创建一个用户,只能访问指定的对象

今天在开发接口时候,需要给接口开发公司提供一个ORACLE 用户,只能访问指定的表或视图,把过程记录到此 1.创建一个ORACLE 的用户 create user username identified by pws; 2.给用户授权   grant connect,resource to username;  grant select on 表或视图名 to username; 到此,这个用户就可以访问指定的表了,可是用户登录 在PLSQL中用 Select * from 表或视频图名;提示表