当前位置: 首页 > article >正文

Spring Boot使用WebSocket

        跟其他http的控制层类似,我们需要实现一个基本的 WebSocket 服务器端点。

PlatformAsyncWebSocket.java
package com.rmeservice.platform.websocket;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ServerEndpoint(value = "/ws/platformAsync/{userId}")
public class PlatformAsyncWebSocket {

    // 用来存储每一个客户端对象对应的 WsController 对象
    private static final Map<String, PlatformAsyncWebSocket> onlineUsers = new ConcurrentHashMap<>();

    // 声明 Session 对象,通过该对象可以给指定的用户发送请求
    private Session session;


    /**
     * 连接建立时被调用
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        this.session = session;
        Map<String, List<String>> requestParameterMap = this.session.getRequestParameterMap();
        List<String> userIds = requestParameterMap.get("userId");
        if (userIds!= null &&!userIds.isEmpty()) {
            String userId = userIds.get(0);
            onlineUsers.put(userId, this);
            log.info("用户 {} 建立 WebSocket 连接成功", userId);
        } else {
            log.warn("连接建立时未获取到有效的 userId");
        }
    }


    /**
     * 接收到客户端消息时被调用
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
            List<String> userIds = requestParameterMap.get("userId");
            if (userIds!= null &&!userIds.isEmpty()) {
                String userId = userIds.get(0);
                log.info("从用户 {} 接收到消息: {}", userId, message);
                // 处理接收到的消息,可根据具体业务需求添加逻辑
            } else {
                log.warn("接收消息时未获取到有效的 userId");
            }
        } catch (Exception e) {
            log.error("处理客户端消息时发生异常", e);
        }
    }


    /**
     * 连接被关闭时调用
     */
    @OnClose
    public void onClose(Session session) {
        try {
            Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
            List<String> userIds = requestParameterMap.get("userId");
            if (userIds!= null &&!userIds.isEmpty()) {
                String userId = userIds.get(0);
                onlineUsers.remove(userId);
                session.close();
                log.info("用户 {} 的 WebSocket 连接关闭", userId);
            } else {
                log.warn("连接关闭时未获取到有效的 userId");
            }
        } catch (Exception e) {
            log.error("关闭连接时发生异常", e);
        }
    }


    /**
     * 推送消息,将消息推送给某个指定的用户
     */
    public void sendMsg(String userId, String message) {
        try {
            PlatformAsyncWebSocket wsController = onlineUsers.get(userId);
            if (wsController!= null && wsController.session.isOpen()) {
                wsController.session.getBasicRemote().sendText(message);
                log.info("向用户 {} 发送消息: {}", userId, message);
            } else {
                log.warn("无法向用户 {} 发送消息,可能是用户未连接或连接已关闭", userId);
            }
        } catch (IOException e) {
            log.error("向用户 {} 发送消息时发生异常: {}", userId, e.getMessage());
            // 可考虑添加重试机制或通知管理员等操作
        }
    }
}

代码解释

  1. 类定义和成员变量

    • @Slf4j:使用 Lombok 提供的注解,自动生成 log 日志对象。
    • @Component:将类标记为 Spring 组件,由 Spring 容器管理。
    • @ServerEndpoint(value = "/ws/platformAsync/{userId}"):将类声明为 WebSocket 服务器端点,客户端可通过 /ws/platformAsync/{userId} 连接。
    • private static final Map<String, PlatformAsyncWebSocket> onlineUsers = new ConcurrentHashMap<>();:存储已连接用户及其对应的 PlatformAsyncWebSocket 实例。
    • private Session session;:存储与客户端的 WebSocket 会话。
  2. onOpen 方法

    • 当 WebSocket 连接建立时,将 session 存储在成员变量中。
    • 从 session 的请求参数中获取 userId,若存在则存储到 onlineUsers 中,并记录连接成功日志;若不存在则记录警告日志。
  3. onMessage 方法

    • 接收到消息时,从 session 的请求参数中获取 userId,若存在则记录接收到的消息及用户信息;若不存在则记录警告日志。
    • 对处理消息的逻辑进行异常处理,将异常记录到日志中。
  4. onClose 方法

    • 连接关闭时,从 session 的请求参数中获取 userId,若存在则从 onlineUsers 中移除并关闭 session,记录关闭信息;若不存在则记录警告日志。
    • 对关闭连接的操作进行异常处理,将异常记录到日志中。
  5. sendMsg 方法

    • 根据 userId 查找 PlatformAsyncWebSocket 实例,若存在且会话打开,发送消息并记录日志;若不存在或会话关闭,记录警告日志。
    • 对发送消息的操作进行异常处理,记录异常信息,可考虑添加重试机制或通知管理员。

       在实际应用中,可能需要考虑更多的业务需求,如消息的协议格式、安全验证、消息队列、负载均衡等。

       对于高并发场景,可以考虑使用更高级的线程同步机制或分布式存储来存储 onlineUsers。 对于异常处理,可以根据具体需求添加更完善的错误处理逻辑,如重试、告警等。


http://www.kler.cn/a/508390.html

相关文章:

  • Vulnhub-Tr0ll靶机笔记
  • vue编写一个可拖动的模块,并可以和任何其他组件组合使用
  • 归并排序算法
  • 无人机技术架构剖析!
  • SUN的J2EE与微软的DNA
  • 港科夜闻 | 香港科大与微软亚洲研究院签署战略合作备忘录,推动医学健康教育及科研协作...
  • 游戏引擎学习第79天
  • 零基础构建最简单的 Tauri2.0 桌面项目 Star 88.4k!!!
  • 【STM32-学习笔记-8-】I2C通信
  • mayavi -> python 3D可视化工具Mayavi的安装
  • GoLang教程003:数据类型介绍
  • Java基础(二)
  • 基于 Spring Boot 和 Vue.js 的全栈购物平台开发实践
  • 正则表达式基础知识及grep、sed、awk常用命令
  • 【JVM-10】IBM HeapAnalyzer 工具使用指南:深入解析 Java 堆转储分析
  • 【微服务】SpringCloud 1-9章
  • R语言绘图
  • go语言gui窗口应用之fyne框架-自定义容器实现自定义布局,更灵活的显示控件
  • sparkSQL练习
  • 使用FineBI进行数据分析(入门级)
  • 天机学堂3-ES+Caffeine
  • 多个页面一张SQL表,前端放入type类型
  • C++实现设计模式---中介者模式 (Mediator)
  • 【机器学习:三十三(一)、支持向量机】
  • YOLOv11改进,YOLOv11检测头融合RFAConv卷积,并添加小目标检测层(四头检测),适合目标检测、分割等任务
  • RV1126+FFMPEG推流项目(7)AI音频模块编码流程