spring boot整合WebSocket实现群聊功能 通俗易懂教程

  1. 首先获取消息的内容,即payload。
  2. 将payload转换为JSONObject对象,并从中获取消息类型type。
  3. 如果消息类型是"join",则从消息中获取群组ID,并将当前WebSocketSession的ID加入到该群组对应的Set中。
  4. 如果消息类型是"leave",则从消息中获取群组ID,并从该群组对应的Set中移除当前WebSocketSession的ID。
  5. 如果消息类型是"message",则从消息中获取群组ID,并获取该群组对应的所有WebSocketSession,逐一向这些Session发送消息。

其中,groups和sessions是两个Map,分别用来存储群组与其对应的WebSocketSessions。computeIfAbsent和computeIfPresent方法分别用来向Map中添加元素和更新元素。sendMessage方法用来向客户端发送消息。

导入依赖

复制代码
        <!-- spring-boot-starter-websocket依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
创建MyWebSocketHandler类
复制代码
import com.songzixain.service.MyWebSocketHandler;
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;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * <p>
 * Description: WebSocketConfig配置类
 * </p>
 *
 * @author 
 * @version 
 * @create 
 * @see 
 */

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*");
创建MyWebSocketHandler类

这段代码是一个WebSocket处理器中的消息处理方法,用来处理WebSocket客户端发送的消息

复制代码
/**
 * <p>
 * Description: MyWebSocketHandler用 来处理WebSocket客户端发送的消息
 * </p>
 *
 * @author 
 * @version 
 * @create 
 * @see 
 */
@Slf4j
public class MyWebSocketHandler implements WebSocketHandler {

    private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
    private static final Map<String, Set<String>> groups = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.put(session.getId(), session);
    }


    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        String payload = message.getPayload().toString();
        log.info("接收到的用户消息 {}", payload);
        JSONObject json = JSON.parseObject(payload);

        String type = json.getString("type");
        //  用户加入了群组
        if ("join".equals(type)) {
            String groupId = json.getString("groupId");
            groups.computeIfAbsent(groupId, k -> new HashSet<>()).add(session.getId());
        } else if ("leave".equals(type)) {
            String groupId = json.getString("groupId");
            groups.computeIfPresent(groupId, (k, v) -> {
                v.remove(session.getId());
                return v;
            });
            // 接收到了用户消息
        } else if ("message".equals(type)) {
            String groupId = json.getString("groupId");
            Set<String> groupSessions = groups.get(groupId);
            for (String sessionId : groupSessions) {
                WebSocketSession s = sessions.get(sessionId);
                if (s != null && s.isOpen()) {
                    s.sendMessage(new TextMessage(payload));
                }
            }
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        sessions.remove(session.getId());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        sessions.remove(session.getId());
        groups.values().forEach(v -> v.remove(session.getId()));
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
}
前端的html测试页面
复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket Chat</title>
</head>
<body>
    <div id="output"></div>
    <input id="input" type="text" placeholder="Type your message">
    <button id="send">Send</button>
    <button id="join">Join Group</button>
    <button id="leave">Leave Group</button>

    <script>
        var socket = new WebSocket("ws://localhost:8080/ws");

        socket.onopen = function(event) {
            console.log("WebSocket connected");
        };

        socket.onmessage = function(event) {
            var message = event.data;
            var output = document.getElementById("output");
            var p = document.createElement("p");
            p.innerText = message;
            output.appendChild(p);
        };

        socket.onclose = function(event) {
            console.log("WebSocket disconnected");
        };

        var sendButton = document.getElementById("send");
        var input = document.getElementById("input");
        var joinButton = document.getElementById("join");
        var leaveButton = document.getElementById("leave");

        sendButton.addEventListener("click", function() {
            var message = {
                userId: "1",
                type: "message",
                groupId: "group1",
                content: input.value
            };
            socket.send(JSON.stringify(message));
            input.value = "";
        });

        joinButton.addEventListener("click", function() {
            var message = {
                userId: "1",
                type: "join",
                groupId: "group1"
            };
            socket.send(JSON.stringify(message));
        });

        leaveButton.addEventListener("click", function() {
            var message = {
                userId: "1",
                type: "leave",
                groupId: "group1"
            };
            socket.send(JSON.stringify(message));
        });
        socket.onmessage = function(event) {
    var message = event.data;
    var output = document.getElementById("output");
    var p = document.createElement("p");
    p.innerText = message;
    output.appendChild(p);
};
    </script>
</body>
</html>

这个WebSocket处理器实现了群聊功能,并支持用户加入和离开群组时向群组中的其他用户发送通知。

启动Spring Boot项目.点击加入群主,然后就可以发送消息了

相关推荐
非优秀程序员9 小时前
第07章 孙德良的阳谋|《互联网产品恩仇录》
javascript·后端
非优秀程序员9 小时前
第06章 浙江帮的内战|《互联网产品恩仇录》
后端
非优秀程序员9 小时前
第08章 马云的反击|《互联网产品恩仇录》
后端
非优秀程序员9 小时前
题记|《互联网产品恩仇录》
后端·程序员·创业
Gopher_HBo13 小时前
Go CPU 剖析的"地基":信号、CAS、写屏障、无锁环形缓冲
后端
panbook13 小时前
从0到1实现一个分布式时序数据库(二):写入成功之后,如何用 WAL 找回数据
后端
Swot14 小时前
上传一张 4MB 图片,我先后撞上了三层请求体限制
后端
IT_陈寒14 小时前
Vite的HMR把我整不会了:一个生产环境的热更新坑
前端·人工智能·后端
OLRainM14 小时前
实习复盘:大模型网关渠道质量评分实战(二)—— 报错了到底算谁的锅?流式归因与 Token 补账踩过的 8 个真坑
后端
梦想恒远14 小时前
Spring Boot + LangChain4j 统计 token 成本:ChatModelListener 实测与单价口径
spring boot·后端