【WEB系列】 实战之基于WebListener实现实时在线人数统计

文章目录
  1. 项目配置
    1. 1. 依赖
    2. 2. 启动入口
    3. 3. web配置
  2. 在线人数统计实现
    1. 1. 计数服务
    2. 2. Session监听器
    3. 3. 登录登出接口
    4. 4. 小结
  3. 不能错过的源码和相关知识点
    1. 0. 项目
    2. 1. 微信公众号: 一灰灰Blog

很多pc网站都有一个实时在线人数的统计功能,那么一般这种是采用什么方式来实现的呢? 这里我们介绍一个最基础的是实现方式,基于Session结合WebListener来实现在线人数统计

项目配置

1. 依赖

首先搭建一个标准的SpringBoot项目工程,相关版本以及依赖如下

本项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发

1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

2. 启动入口

我们使用默认的配置进行测试,因此启动入口也可以使用最基础的

1
2
3
4
5
6
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}

3. web配置

我们主要根据用户的session来创建与销毁来判断是否有新的用户访问站点、以及长时间没有访问之后认为已经离线,为了简化这个注销的模拟过程,我们将session的生命周期设置短一点

1
2
3
4
5
server:
port: 8081
servlet:
session:
timeout: 1m # 设置1分钟的有效时间

在线人数统计实现

接下来我们看一下具体的实现思路:

  • 借助Servelt的Listener机制,主要监听Session的创建与销毁
  • 当session创建时,认为新来一个用户,计数+1
  • 当session销毁时,认为用户已经离开,或者长时间没有访问,计数-1

1. 计数服务

一个简单基础的计数服务,借助 AtomicInteger 来实现计数统计(为啥不直接是int ?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class CountService {

private AtomicInteger cnt = new AtomicInteger(0);

public void incr(int cnt) {
this.cnt.addAndGet(cnt);
}

public int getOnlineCnt() {
return cnt.get();
}

}

2. Session监听器

自定义一个Session的监听器,监听HttpSession的相关操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@WebListener
public class LoginUserCountListener implements HttpSessionListener {
@Autowired
private CountService countService;

@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("--------- 新增一个用户 ------- session = " + se.getSession().getId());
HttpSessionListener.super.sessionCreated(se);
countService.incr(1);
}

@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("--------- 销毁一个用户 -----------" + se.getSession().getId() + " = " + se.getSession().getAttribute("name"));
HttpSessionListener.super.sessionDestroyed(se);
countService.incr(-1);
}
}

3. 登录登出接口

最后再设计一个登录、登出、查询实时在线人数的统计接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@RestController
public class LoginController {
@Autowired
private CountService countService;

@RequestMapping(path = "/login")
public String login(String uname, HttpSession httpSession) {
httpSession.setAttribute("name", uname);
System.out.println("登录成功:" + uname);
return "欢迎登录:" + uname + ", 当前在线人数: " + countService.getOnlineCnt();
}


/**
* 查询当前在线人数
*
* @param session
* @return
*/
@RequestMapping("online")
public String showOnlineUser(HttpSession session) {
return session.getAttribute("name") + " ,当前时间为:" + LocalDateTime.now() + " 在线人数:" + countService.getOnlineCnt();
}

@RequestMapping(path = "logout")
public String logout(HttpSession httpSession) {
// 注销当前的session
httpSession.invalidate();
return "登出成功, 当前在线人数: " + countService.getOnlineCnt();
}
}

接下来验证一下,实时在线人数统计情况

4. 小结

上面虽然是实现了实时在线人数统计,但是存在一个非常明显的短板问题,那就是只适用于单机的场景,如果后台有多个服务部署,那应该怎么处理呢?

基于此,自然而然想到的就是分布式session 结合 redis 计数来实现,但是这个思路可行么? 分布式session失效会抛出一个事件么?或许通过监听redis的key失效能处理,但是整体来看,还是有些麻烦,有没有更简单实用的场景呢

且待下文详解

不能错过的源码和相关知识点

0. 项目

1. 微信公众号: 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

一灰灰blog


打赏 如果觉得我的文章对您有帮助,请随意打赏。
分享到