Spring Boot整合WebSocket和Redis实现直播间在线人数统计功能

😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志

🎐 个人CSND主页------Micro麦可乐的博客

🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战

🌺《RabbitMQ》专栏主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战

🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解

💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程

🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整

如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

Spring Boot整合WebSocket和Redis实现直播间在线人数统计功能

前言

在现在这个短视频时代,很多企业也投入到了直播的行业,甚至为了打造自己专属私域某些企业也会开发应用自己的直播系统,而在直播应用中,实时显示在线人数是一个非常重要的功能。

这里博主将详细介绍通过结合 Spring BootWebSocketRedis ,我们可以实现一个简单而高效的直播间在线人数统计功能,并提供完整的代码示例。

简单了解WebSocket和Redis

WebSocket是一种在单个TCP连接上进行全双工通信的协议,适用于需要实时数据更新的应用。Redis是一个高性能的键值存储系统,常用于缓存和消息队列。在这里博主将将使用WebSocket来监控用户的连接状态,并使用 Redis 来存储和统计在线人数。

开发准备

步骤一:添加依赖

首先构建我们的 Spring Boot 项目, 引入相关依赖 WebSocketRedis 的依赖

xml 复制代码
<dependencies>
	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

步骤二:配置Redis

由于Spring Boot自动装配的原理,我们只需要在配置文件设置 Redis 的连接参数,在需要使用Redis的地方注入 RedisTemplate 即可

yml 复制代码
spring:
    #redis
    redis:
        # 地址
        host: 127.0.0.1
        # 端口,默认为6379
        port: 6379
        # 数据库索引
        database: 0
        # 密码
        password:
        # 连接超时时间
        timeout: 10s
        lettuce:
            pool:
                # 连接池中的最小空闲连接
                min-idle: 5
                # 连接池中的最大空闲连接
                max-idle: 8
                # 连接池的最大数据库连接数
                max-active: 20
                # #连接池最大阻塞等待时间(使用负值表示没有限制)
                max-wait: -1ms

步骤三:定义WebSocket处理器

创建一个 WebSocket理器类WebSocketHandler继承TextWebSocketHandler,用于处理WebSocket消息和连接事件

java 复制代码
package com.toher.dockertestproject.live;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class WebSocketHandler extends TextWebSocketHandler {

    //定义redis key
    private static final String LIVE_ROOM_USER_KEY = "liveRoomUsers";
    //注入RedisTemplate
    private final StringRedisTemplate redisTemplate;
    //使用集合存储每个用户WebSocket会话
    private final Set<WebSocketSession> sessions = Collections.newSetFromMap(new ConcurrentHashMap<>());

    public WebSocketHandler(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 建立连接后
     * @param session 连接会话
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
        //调用increment方法进行自增操作
        redisTemplate.opsForValue().increment(LIVE_ROOM_USER_KEY);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String userId = message.getPayload();
        // 拟获取用户Id 后返回用户信息
        String userName = "匿名用户";
        if(userId.equals("1")){
            userName = "榜一大哥:小明";
        }
        if(userId.equals("2")){
            userName = "榜二大姐:小羊";
        }
        session.sendMessage(new TextMessage("user:"+userName));
        broadcastOnlineCount();
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        //集合删除会话
        sessions.remove(session);
        //调用increment方法进行自减操作
        redisTemplate.opsForValue().decrement(LIVE_ROOM_USER_KEY);
        broadcastOnlineCount();
    }

    private void broadcastOnlineCount() {
        String count = redisTemplate.opsForValue().get(LIVE_ROOM_USER_KEY);
        TextMessage message = new TextMessage("count: " + count);
        for (WebSocketSession session : sessions)
            try {
                session.sendMessage(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
}

步骤四:编写WebSocket配置类

定义 WebSocket 配置类,并添加注解 @EnableWebSocket 开启 WebSocket 支持

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    //注入WebSocket处理器
    private final WebSocketHandler webSocketHandler;

    public WebSocketConfig(WebSocketHandler webSocketHandler) {
        this.webSocketHandler = webSocketHandler;
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler, "/ws")
                .setAllowedOrigins("*");
    }
}

步骤五:编写简单的前端页面

创建一个简单的前端页面,URL传递参数用户ID用于模拟后端获取用户信息返回,创建一个id元素用于连接WebSocket并显示在线人数

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>欢迎来到麦可乐的直播间</title>
</head>
<body>
    <h1>直播间人数: <span id="onlineCount">0</span></h1>
	<h2 id="user"></h2>
    <script type="text/javascript">
		
		const params = new URLSearchParams(window.location.search);

        let socket = new WebSocket("ws://localhost:9090/ws");

        socket.onmessage = function(event) {
        	//获取后端传递的数据 格式 xxx:xxx
			let data = event.data.split(":");
			if(data[0]=='user'){
				let user = `欢迎 ${data[1]} 进入我直播间`
				document.getElementById("user").innerText = user;
			}else{
				document.getElementById("onlineCount").innerText = data[1];
			}
        };

        socket.onopen = function(event) {
			//模拟发送用户ID 
			socket.send(params.get('userId'));
            console.log("创建WebSocket会话");
        };

        socket.onclose = function(event) {
            console.log("关闭WebSocket会话");
        };
    </script>
</body>
</html>

开始测试

将前后端项目运行,打开多个浏览器窗口(不是标签页!不是标签页!不是标签页!),测试访问

可以看到如上图所示,当新窗口进入了前端地址直播间人数+1,关闭窗口或所在标签页直播间人数-1

总结

通过本文的步骤,我们成功地在Spring Boot项目整合WebSocket和Redis实现了一个直播间在线人数统计功能。这个解决方案不仅能够实时更新在线人数,还能有效地处理高并发场景。

本文的代码主要是演示使用,小伙伴们可以根据自己业务需求进行修改升级。如果本文对您有所帮助,希望 一键三连 给博主一点点鼓励,如果您有任何疑问或建议,请随时留言讨论。


相关推荐
摇滚侠17 分钟前
Spring Boot 3零基础教程,WEB 开发 整合 Thymeleaf 笔记36
java·spring boot·笔记
optimistic_chen1 小时前
【Java EE进阶 --- SpringBoot】Mybatis - plus 操作数据库
数据库·spring boot·笔记·java-ee·mybatis·mybatis-plus
来旺2 小时前
互联网大厂Java面试全解析及三轮问答专项
java·数据库·spring boot·安全·缓存·微服务·面试
摇滚侠2 小时前
Spring Boot 3零基础教程,yml文件中配置和类的属性绑定,笔记15
spring boot·redis·笔记
thginWalker2 小时前
使用Spring Boot构建消息通信层
spring boot
lang201509282 小时前
Spring Boot 外部化配置最佳实践指南
java·spring boot
摇滚侠2 小时前
Spring Boot 3零基础教程,WEB 开发 HTTP 缓存机制 笔记29
spring boot·笔记·缓存
Knight_AL2 小时前
Spring Boot 中使用自定义注解和 AOP 实现微服务日志记录(包含 URL、状态码和耗时信息)
linux·spring boot·微服务
cr7xin2 小时前
基于Session和Redis实现短信验证码登录
数据库·redis·缓存
Q_Q19632884752 小时前
python+vue的在线租房 房屋租赁系统
开发语言·vue.js·spring boot·python·django·flask·node.js