统计在线用户人数,用户一登陆,在线人数加一,注销时在线人数减一,如果用户直接把浏览器关了或者非法退出?
我如何才能知道?并且能够在他非法退出时,对应的在线人数减一,而不是用户已经退出了,在线人数却没有改变?
用了监听器来做处理,在sessionDestroyed方法定义:public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
        ServletContext application = session.getServletContext();        // 取得登录的用户名
        String username = (String) session.getAttribute("username");
        List<String> users=(List) application.getAttribute("users");
        users.remove(username);
        System.out.println("非法退出,注销此用户:"+username); }
在调用session.invalidate();会自动执行此方法,但如果我直接关闭浏览器,这个方法不会被执行!求救高手了!

解决方案 »

  1.   

    你用JavaScript的window.onbeforeunload事件试试
    页面卸载时再执行用户注销
      

  2.   

    可以用javascript做辅助,但不应该依赖它。如果人家直接结束进程,甚至PC直接断电,服务器又如何得知?
    楼主你现在做的已经可以了。session会超时的,超时了就自动销毁了。
      

  3.   

    1楼的所说onbeforeunload这个方法也试过,但如果页面有链接的话,它也会默认调用onbeforeunload方法,
    如果我想链接到别的页面,结果session却已经把用户清除了,其实此时用户是应该还保存在session范围里的。
    超时是可以解决,但如果我有一张用户表User,有个字段state,(0为不在线,可以登陆;1为在线,不能重复登陆),
    我想登陆时,判断其state是否为0,为0才可以登陆,并且登陆成功后设置其状态为1,(防止重复登陆),用户退出时,再把
    其状态设为0。如果按LS所说,直接断电或者非法退出时,其状态就不能修改了,还是1,下次再登陆时,岂不是无法登陆吗?
      

  4.   

    可以设置与服务器的连接时间
    超过这个时间的话session就失效
      

  5.   

    还有大家看清题目,我说了用了session监听器,直接关闭浏览器,监听器还是没有起作用的!
    设置时间的话,还是不灵活,有没有更好的办法?
      

  6.   

    等高手.现在所知的就只有等session超时了
      

  7.   

    首先在用户登录的时候将用户信息及sessionId放入一个对象内,这个对象除了以上两种信息还要包括用户最后刷新时间,登录时就是登录时间。
    再写一个单例的对象,内部保存已登录用户信息集合,同时开一个线程定时查询登录用户信息集合内当前系统时间-用户最后刷新时间是否超过默认的超时时间,如果超过则判定用户已退出。
    最后在各个页面内要用Ajax技术及setTimeout函数定时向服务器发送请求,以刷新用户最后刷新时间。
    要注意的是页面内的刷新间隔、服务端定时判定超时的线程的启动间隔及默认超时时间。
      

  8.   


    目前来说,楼主是不会得到满意答案,除非你能通过你的WEB服务器主动给每个登陆上来的客户端发信息。目前,你认为可能吗?
      

  9.   

    web应用本身就请求-响应模式,它不是实时的,你如何能实时监控状态?你能做的就是如果多久不再请求,就怎么怎么样;
      

  10.   

    是不是IE的缓存,从而使session的值并没有马上清除?
      

  11.   

    我暂时想的办法是监听器,session创建时加1,session消回时减1,再设置session超时时间
      

  12.   

    恩,要执行sesssion.invalidate()才可以注销掉session;
    我之前做过,不过这个方法不怎么好,但能实现
    //关闭浏览器的时候:
    function window.onunload(){
    window.location.href="/saizi/room.jsp";
    }
    //room.jsp的代码:这个网页可以自动关闭,不弹出提示.  <% session.invalidate(); %>
      <script type="text/javascript">
      window.open("","_self");
      window.close();
      </script>
    跟着就会马上调用session监听的sessionDestroyed()去减去一个用户,,
      

  13.   

    如果在此页面有个链接的话,当我点击时,他会默认跳转到room.jsp的,所以虽然直接关闭可以实现这个功能,但如果里面有超链接的话就不好使了!
      

  14.   

    用Session监听器,试下吧。将Session存活时间设短点
    一、实现Session监听器
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;public class OnlineCounter implements HttpSessionListener {public synchronized void sessionCreated(HttpSessionEvent se){
       String count = (String)se.getSession().getServletContext().getAttribute("count");
       int c=0;
       if(count !=null){
        c = Integer.valueOf(count).intValue();
        System.out.println("旧Count:"+c);
        se.getSession().getServletContext().setAttribute("count",(c+1)+"");
       }else{
        System.out.println("新Count");
        se.getSession().getServletContext().setAttribute("count",c+1+"");
       }
       System.out.println("建立session时 Count:"+c);
    }public synchronized void sessionDestroyed(HttpSessionEvent se){
       System.out.println("session失效时 ");
       String count = (String)se.getSession().getServletContext().getAttribute("count");
       int c=0 ;
       if(count !=null){
        c = Integer.valueOf(count).intValue();
        if(c>=1){
         System.out.println("sessionDestroyed:旧c-1:"+c);
         se.getSession().getServletContext().setAttribute("count",(c-1)+"");
        }
       }else{
        System.out.println("sessionDestroyed:旧新"+c);
        se.getSession().getServletContext().setAttribute("count","1");
       }
       // session失效时
    }
    }
    二、配置Session监听器 与Session存活时间<listener>
            <listener-class>
                com.longqiao.tools.servlet.OnlineCounter
            </listener-class>
        </listener>
    <session-config>
        <session-timeout>1</session-timeout> <!-- Session存活时间为1分钟 -->
    </session-config>三、从前台提出网站在线人数...当前在线人数:${applicationScope.count}
      

  15.   

    感谢楼上的帮助,但我有个疑问,我把session的存活时间设为1分钟,
    如果用户在线时间超过1分钟,是不是用户就得自动下线了啊?
      

  16.   

    没有好的方法就session设短点吧
      

  17.   

    我也有这样的问题...一直都想不太明白.我在想能不能点关闭时跳到另一个页面,那个页面写清session的方法,再在几秒关闭此页.
      

  18.   

    用ASP和VBScript:
    <% If Not Response.IsClientConnected Then ...%>
      

  19.   

    很抱歉ASP和VBscript我都不会用!
      

  20.   

    只要能在javascript中写代码就很简单的去除session中的某个对象啊!!
      

  21.   


    估计有点难!因为不是实时的,而且别人关闭时也不可能先和你打招呼的!
    最多只能是在页面里加行代码,在正常关闭的时候给服务器发个消息,来注销session!
      

  22.   

    有个想法哈,有没有什么方法可以统计出有多少个sessionId,直接根据sessionId数量判断在线人数呢
      

  23.   

    这个问题好多人已经讨论过了,如果是纯粹的web程序感觉很难做到高效的解决.
    如果你非要解决的话也不是没有办法,但你要为此付出很大的代价.比如你可以用
    服务器推技术,这时候你的程序已经跟c/s程序没有太大区别了,因为是实时连接
    的,客户端掉了立即就可以察觉出来。但这样的话你的服务器所能处理的连接数就
    很少了。用flash或applet和服务器端进行socket通信业可以实现服务器推,但这样做
    有什么缺点,不用说大家也知道了。你自己权衡吧为了这点功能是否值得去做这些牺牲.
    这有服务器推技术的一点资料,你可以参考下。做毕业设计的时候找到的,很久没弄了
    http://www.ibm.com/developerworks/cn/web/wa-lo-comet/
      

  24.   

    有个想法哈,有没有什么方法可以统计出有多少个sessionId,直接根据sessionId数量判断在线人数呢 真的可以诶
      

  25.   

    难道这个问题在web开发中也属于不治之症吗?求名医啊!~
      

  26.   

    我不明白 超过SESSION的过期时间SESSION就会自动销毁 跟浏览器没啥大关系吧?
      

  27.   

    这样可以达到楼主的要求:
    1. 用户登录时,将 session 对象缓存到唯一实例对象中[这个对象中包含一个Map对象(key: loginName, value: session对象)];
    2. 在sessionListener中清除正常退出或超时退出的用户session (同时从前面的Map对象中清除);
    3. 相同登录名的用户登录时,首先缓存sessionId到另一个Map对象中(Key: sessionId, value: null),然后自动结束之前登录用户的session(就是让session立即过期),并同时从前面的Map对象中清除(使用loginName清除);
    4. 使用一个Filter程序,接收其请求中的sessionId(即:request.getRequestedSessionId();),判断该sessionId是否在Map对象中,如果是,则直接跳转到错误页面并提示“您的账号被重复登录,因此您已被强制退出,请重新登录。”这样,后者将前者踢出,就不存在后来者不能登录的情况了;之前登录的用户被踢出后,再次请求时,会自动显示被踢出的提示信息。另:加上一个配置选项,就可实现是否允许重复登录的功能。
      

  28.   

    这样可以达到楼主的要求: 
    1. 用户登录时,将 session 对象缓存到唯一实例对象中[这个对象中包含一个Map对象(key: loginName, value: session对象)]; 
    2. 在sessionListener中清除正常退出或超时退出的用户session (同时从前面的Map对象中清除); 
    3. 相同登录名的用户登录时,首先缓存sessionId到另一个Map对象中(Key: sessionId, value: null),然后自动结束之前登录用户的session(就是让session立即过期),并同时从前面的Map对象中清除(使用loginName清除); 
    4. 使用一个Filter程序,接收其请求中的sessionId(即:request.getRequestedSessionId();),判断该sessionId是否在Map对象中,如果是,则直接跳转到错误页面并提示“您的账号被重复登录,因此您已被强制退出,请重新登录。”,并从该Map对象中清除该sessionId。这样,后者将前者踢出,就不存在后来者不能登录的情况了;之前登录的用户被踢出后,再次请求时,会自动显示被踢出的提示信息(仅可提示一次)。 另:加上一个配置选项,就可实现是否允许重复登录的功能。
      

  29.   

    以上的Map对象中,注意要使用支持同步功能的Map实现(可使用java.util.Collections.synchronizedMap(Map m)方法对普通Map对象进行同步封装处理)。
      

  30.   

             /*关闭窗体时向服务器发送请求清空session中的对象*/
    function window.onunload()   
    {   
    if(event.clientX>document.body.clientWidth&&event.clientY<0||event.altKey||event.ctrlKey)   
    {   
        var rightId = document.forms[0].elements("rightId").value;
        self.location.href="./AAA.do?actionMethod=doDestroy&rightId="+rightId;
        window.close();
    }   
    }     LZ 用这个方法试试
      

  31.   

    //onunload() 和 beforunload() 都是浏览器刷新和关闭的事件,区别在于beforunload比onunload先执行
    function window.onunload()  
    {  
      //这个IF用于判断是刷新还是关闭,如果是关闭就进入下面代码href去ACTION中请求销毁session对象
     if(event.clientX>document.body.clientWidth&&event.clientY <0||event.altKey||event.ctrlKey)  
     {  
        var rightId = document.forms[0].elements("rightId").value; 
        self.location.href="./AAA.do?actionMethod=doDestroy&rightId="+rightId; 
        window.close(); 
     }  
    }  event.clientX鼠标的x坐标
    document.body.clientWidth 视窗宽度
    event.clientY鼠标的y坐标
    event.altKey alt键 event.ctrlKey 雷同回复当前鼠标x坐标值大于文档宽度并且鼠标y坐标值小于0或者alt键被按下或者ctrl键被按下
      public ActionForward doDestroy(ActionMapping mapping, ActionForm form,
                HttpServletRequest request, HttpServletResponse response)
        {
         if(request.getSession().getAttribute("XXXVO")!=null)
         {
         request.getSession().removeAttribute("XXXVO");
         }
         return null;
        }
    当然也有问题,比如浏览器的问题,突然断电等问题,我是没去试过。只是给你个建议吧 呵呵
      

  32.   

    你非要这么做也不是不可以把session时间设置得非常非常短;例如10秒;
    然后写一个js,用ajax在后台,定时(每2秒)刷一个心跳页面用来维持session的时效;这样用户不管什么原因,只要那个页面关掉了,js脚本就不会被执行,没有心跳,10秒后自然就下线了这样可以解决用户在这个页面但是很久不动作的情况但是有对于管服务器还是客户端开销增加的弊端
      

  33.   

    刚没注意看,benjamin_liu 同学已经说的很清楚了;
    不是不行,是有没有必要的问题,因为你要把请求-响应 模式改变成 实时模式,开销肯定很大;
      

  34.   

    在页面做定时刷新,setInterval();通过这个方法用ajax与后台进行通讯,如果后台接不到通讯内容就表示下线了,应该就比较容易控制了吧
      

  35.   


    function onLine(){
    createXMLHttpRequest();
    var url = "servlet/innerCommManageServlet.do?action=onLine&userName=${employee.userName}";
    xmlHttp.open("get",url,true);
    xmlHttp.onreadystatechange = onMessage;
    xmlHttp.send(null);
    }

    function onMessage(){
    if(xmlHttp.readyState == 4){
    if(xmlHttp.status == 200){

    }
    }
    }

    window.onload =function(){
     setInterval("onLine()",5000);
    } 我以前好像做过这样的项目
      

  36.   

    同意23楼提的方法,session不可能精确的跟踪,只有判断用户是否有新的请求来确定用户是否超时!
      

  37.   

    79楼提供的方法试过了,在IE下可以执行,在firefox和傲游中不能执行,
    应该是判断的问题:
    if(event.clientX>document.body.clientWidth&&event.clientY <0||event.altKey||event.ctrlKey)  
    这个判断用在IE上可以,如果要兼容其他浏览器该如何写?
      

  38.   

    这个现在还没有完美的解决方法。我试过用JS辅助实现的,能处理用户点击X关闭浏览器,Alt+F4关闭、Ctrl+W关闭、文件菜单项关闭。但是如果用户直接在地址栏中输入网址转到其它网站时,就没办法了
      

  39.   

    利用javascript监听窗体的关闭事件
      

  40.   

    另外就是js的话你怎么判断他是否关闭了全部的网页,如果都加上的话,很显然不可取的,session会自动销毁的。
      

  41.   

    这个问题原本就没必要做如此麻烦的处理,只要把非正常退出的因素全都做session超时处理就行了,只是在线人数的精确度滞后一个session超时的时间段而已,不过在线人数也不用那么精确吧