springboot 用监听器统计在线人数【测试通过】

迈不过友情╰ 2022-11-02 00:54 386阅读 0赞

本文在springboot 的项目,用HttpSessionListener 监听器(监听器的其中一种) 统计在线人数,实质是统计session 的数量。

思路很简单,但是有个细节没处理好,让我调试了大半天,才把bug搞好。

先写个HttpSessionListener 监听器。count 是session的数量(人数),session 创建的时候,会触发监听器的sessionCreated 方法,session销毁的时候,会触发监听器的sessionDestroyed 方法。 在监听器中计算完人数count,把他放进servletContext(可以理解为一个仓库,任意请求可以存储和获取里面的属性)。

注意监听器加上@WebListener,这样就不用配置。

但启动类要加上注解@ServletComponentScan,这样才能扫描到监听器








1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@WebListener

public class OnLineCount implements HttpSessionListener {

    public int count=0;//记录session的数量

    //监听session的创建,synchronized 防并发bug

    public synchronized void sessionCreated(HttpSessionEvent arg0) {

        System.out.println(“【HttpSessionListener监听器】count++  增加”);

        count++;

        arg0.getSession().getServletContext().setAttribute(“count”, count);

  

    }

    @Override

    public synchronized void sessionDestroyed(HttpSessionEvent arg0) { //监听session的撤销

        System.out.println(“【HttpSessionListener监听器】count—  减少”);

        count—;

        arg0.getSession().getServletContext().setAttribute(“count”, count);

    }

}

接着写一个查询session 数量的controller,我开始的时候是像下面这样写的,是错误的!

从servletContext 中取出count ,把count返回前端。








1

2

3

4

5

6

@RequestMapping(“/count”)

@ResponseBody

public String count(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){

    Object count=httpServletRequest.getServletContext().getAttribute(“count”);

    return “count : “+count;

}

这样是错误的,测试你会发现,页面看到count 是null ,因为没有创建session,没有触发监听器的统计方法。于是改一下:








1

2

3

4

5

6

7

8

9

10

@Controller

public class IndexController {

    @RequestMapping(“/count”)

    @ResponseBody

    public String count(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){

        HttpSession session = httpServletRequest.getSession();

        Object count=session.getServletContext().getAttribute(“count”);

        return “count : “+count;

    }

}

 

HttpSession session = httpServletRequest.getSession(); 作用:该用户如果没有sesision则创建session ,有则取得session不创建。

改成这样测试,看起来是对的,但是有个问题。一个浏览器对应一个session,你打开2个浏览器,看到count是2 ,是对的。但是你关了一个浏览器,再打开,应该是2不变才对,但是变成3 了,原因是session销毁的方法没有执行,重新打开时,服务器找不到用户原来的session ,重新创建了一个session,于是有3个session了,但是浏览器只有2个,也就是模拟应该是只有2个人在线上。

有2个方法可以解决这个问题,一个是在关闭网页的时候,前端去调用一个方法把session销毁。另一个更好的方法是,让服务器记得原来那个session,即把原来的sessionId 记录在浏览器,下次打开时,把这个sessionId发送过去,这样服务器就不会重新创建。

代码修改如下:








1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

@Controller

public class IndexController {

    @RequestMapping(“/count”)

    @ResponseBody

    public String number(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){

        try{  //把sessionId记录在浏览器

            Cookie c = new Cookie(“JSESSIONID”, URLEncoder.encode(httpServletRequest.getSession().getId(), “utf-8”));

            c.setPath(“/“);

            //先设置cookie有效期为2天,不用担心,session不会保存2天

            c.setMaxAge( 4860  60);

            httpServletResponse.addCookie(c);

        }catch (Exception e){

            e.printStackTrace();

        }

  

        HttpSession session = httpServletRequest.getSession();

        Object count=session.getServletContext().getAttribute(“count”);

        return “count : “+count;

    }

}

测试达到效果。

然后关闭浏览器,发现没有触发sessionDestroyed,然后怀疑是不是这个监听器的机制有问题,等了好几分钟都没有反应。
后来想起session是有一个超时时间的,浏览器关闭其实对于web服务器来说是不知道的,所以他需要等待超时时间到了之后自动销毁,上面关闭浏览器之后只所以没有促发sessionDesroyed,就是因为默认的超时时间没到。
默认超时时间太长了,所以在sessionCreated中添加如下代码,改小超时时间:
arg0.getSession().setMaxInactiveInterval(15);
这样只要用浏览器访问该站点,然后15s不刷新之后,sessionDestroyed就会被自动调用了。一般不用设置这个超时时间,到了一定时间会自动销毁。

-— end —-

发表评论

表情:
评论列表 (有 0 条评论,386人围观)

还没有评论,来说两句吧...

相关阅读

    相关 监听器统计在线人数

            接着,我来写一个监听器的案例来巩固学习监听器的知识,便于日后的查阅和复习。大概分为以下几个步骤: 1.编写统计人数的Servlet,实现特定的监听器接口 2