• 14. 实例


    使用监听器实现在线客户统计

    统计连接在应用上的客户端数量。客户端的唯一标识就是 IP,只需要对连接到服务器上
    的 IP 数量进行统计,就可统计出客户端的数量。很多人都是只监听了session,即当session创建时,在线客户端的数量就+1,session销毁时,在线客户端的数量就-1,这种统计的方法不正确,因为用户在同一台机器上打开两个不同的浏览器访问系统时,系统会创建两个session对象,如果按照上面方式统计的话当前在线客户有两个,而实际上只有一个,因此需要通过客户端的ip地址来判断的方式更加准确。

     

    这是分析图 已经很明确了,但是要更明确 应该懂得 Session 的 生存 和 销毁。

    我们代码思路大体这样写:

    主要思路是 用 Ip【一个用户】 来装Session【不同浏览器】,Map容器【Map不允许重复 且 映射型容器】

    1.首先注册 ServletContext的监听器,因为服务器启动ServletContext才会生成,且 Servlet 只有一个,所以它创建时,我们就初始化容器【装Session】,将容器放入 ServletContext。

    2.  【这里的List 是对应 一个用户【IP】的! 别混淆!】  监听Request 的创建,然后我们获取到他的 IP,顺便将他的IP放入Session中【Session销毁用的到】然后根据IP获取到它的List【Session容器】,判断一下List是不是为null,如果是null的话 证明第一次访问【无装载记录】 ,第一次访问我们将他的List【Session容器】 赋予地址。

    其次我们获取到他 当前的Session【第一次访问Session就会自动生成】,然后遍历他的 list ,如果 当前Session 和 list中 任意一个 的Session 相同,证明当前用户还在会话【没掉线】,那就Return处理,

    如果 遍历 list 都没找到当前Session 证明 当前 Session 是 最新添加的,我们将其放入 list 中,然后我们更新Map中的List,再更新Servlet中的Map。 【 这里的更新分别指的是替换【Map 替换】 和 【ServletContext 的 Attribute 替换】 】。

    3.监听Session的销毁

    Session销毁【失效】的默认时间是30 分钟,你要自己去设置他的超时时间,优先级也是范围小 到 范围大的! 这里推荐点击注销的时候 用 java 代码直接 杀掉 Session。

    当Session销毁时,证明用户的浏览器掉线了,所以我们获取到被销毁的Session对象,然后根据 IP 【Request监听里面已经设置】 获取到List,然后把这个失效的Session对象 从 List中移除,

    然后我们判断list是不是为空,size = 0?  如果size 是 0 的话 我们直接把 ip 从 Map 中 移除, 证明整个用户直接掉线了。 最后记得要更新!  【这里的更新分别指的是替换【Map 替换】 和 【ServletContext 的 Attribute 替换】 】。

    4.监听记得在XML配置中加配置

    代码:

    MyServletContextListener.java:

    package onlineNumber;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.http.HttpSession;
    
    /**
     * 监听ServletContext    
     * @author Bi-Hu
     *
     */
    public class MyServletContextListener implements ServletContextListener {
    
        //当ServletContext 创建时 我们做:
        @Override
        public void contextInitialized(ServletContextEvent sce) {
        //首先新建IP容器Map
         Map<String, List<HttpSession>> ipMap = new HashMap<>();    
         
         //然后我们    获取Context -> 把ip容器放入Map
         ServletContext sc = sce.getServletContext();
         sc.setAttribute("ipMap", ipMap);
        }
        
        
    
    }

    MyRequestListener.java

    package onlineNumber;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    /**
     * 监视Request 当Request创建时 我们根据IP判断是不是新访问,如果是新建一个List给他装Session 然后更新到Map【关键】 不是的话 直接Return
     * @author Bi-Hu
     *
     */
    public class MyRequestListener implements ServletRequestListener {
    
        
        @Override
        public void requestInitialized(ServletRequestEvent sre) {
            //获取Request
            HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
            
            //获取ipMap
            ServletContext sc = request.getServletContext();
            Map<String, List<HttpSession>> ipMap = (Map<String, List<HttpSession>>)sc.getAttribute("ipMap");
            
            //获取ip 然后根据ip找list 看下是否第一次登录 或 重新登录
             String Ip = request.getRemoteAddr();
             System.out.println(Ip);
            
            
             List<HttpSession> list = ipMap.get(Ip);
             if(list == null) {
                 list = new ArrayList<HttpSession>();
             }
             
    
             
             //获取当前Session【你获取了 不存在会新建】,然后判断list中有没有你这个Session ,如果没有代表你是新Session 如果存在就结束
             HttpSession CurrentSession = request.getSession();
             for(HttpSession s : list) {
                 if(s == CurrentSession) {    
                    //如果重复 代表你还在会话中 
                     return;
                 }
             }
             
             //如果不存在 就执行到这里了 代表你是新建的Session 那么就会进行更新:【这一步很重要!!】
             //把新建的Session放入list
             list.add(CurrentSession);
             ipMap.put(Ip, list);                //更新list
             sc.setAttribute("ipMap", ipMap);    //更新ipMap
             
             //顺便把当前Ip放入 Session中
             CurrentSession.setAttribute("ip", Ip);        //销毁Session时用的到
            System.out.println("Ip为:"+ Ip +"中的 Session 个数: " + ipMap.get(Ip).size() + "个");
            
        }
    
        
    }

    MySessionListener.java

    package onlineNumber;
    
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    import javax.websocket.Session;
    
    /**
     *     监视Session销毁时 你销毁 我就把你删除 ,然后判断list是否为空 为空的话 用户就离线了 所以我们把List给Kill掉
     * @author Bi-Hu
     *
     */
    public class MySessionListener implements HttpSessionListener {
    
        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            //先获取到他的Session
            HttpSession CurrentSession = se.getSession();
            ServletContext sc = CurrentSession.getServletContext();
            String CurrentIp = (String) CurrentSession.getAttribute("ip");
    
            
            
            //然后我们根据IP找到他的 List 然后在List中移除这个Session【销毁的】
            Map<String, List<HttpSession>> ipMap = (Map<String, List<HttpSession>>) sc.getAttribute("ipMap");
            List<HttpSession> list = ipMap.get(CurrentIp);
            list.remove(CurrentSession);
            
            System.out.println("ID 为" + se.getSession().getId() + " 的 Session 销毁了");
            System.out.println("Ip为:"+ CurrentIp +"中的 Session 个数: " + ipMap.get(CurrentIp).size() + "个");
            
            //然后我们判断list还有么有元素 没有的话 证明用户离线了 那我们把它的Id 删除 然后更新 就收工
            if(list.size() == 0) {
                ipMap.remove(CurrentIp);
            }else {
                ipMap.put(CurrentIp, list);        //更新List
            }
            
            sc.setAttribute(CurrentIp, ipMap);    //总更新【重要】
            System.out.println("还剩在线用户:" + ipMap.size());
            
        }
    
        
    }

    我在这里设置了 1分钟Session 失效  这样就很快看的出 在线 /  离线 的对比了

    电脑的火狐 会用 127.0.0.1  谷歌 和 其他浏览器均是0.0.0.0.1

    所以会有两个用户 Session 的对比也能看得出来 目标完成。

     成功图:

    谢谢。 

    本文来自博客园,作者:咸瑜,转载请注明原文链接:https://www.cnblogs.com/bi-hu/p/14861493.html

  • 相关阅读:
    System Verilog 片断
    如何避免covergroup中出现错误
    一种FPGA图像处理算法的快速验证方式
    什么才是一个feature to be test?
    我的第一份vPlan衍变路线
    思想误区解答:请专注于DUT的功能(全部为菜鸟个人总结不保证正确)
    谈谈验证中的SystemVerilog和CPP//转载
    ResourceBundleViewResolver
    springmvc json数据返回前台,中文乱码
    将字符串中间的某段长度替换成固定的值
  • 原文地址:https://www.cnblogs.com/bi-hu/p/14861493.html
Copyright © 2020-2023  润新知