SpringBoot3-整合WebSocket指南

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞??收藏评论

SpringBoot3-整合WebSocket指南
  • 1. 什么是WebSocket?
  • 2. 环境准备
    • 2.1 项目依赖
  • 3. WebSocket配置
    • 3.1 WebSocket配置类
    • 3.2 自定义WebSocket处理器
  • 4. 控制器
  • 5. 前端实现
    • 5.1 HTML页面
  • 6. 测试WebSocket功能
  • 7. 进阶功能
    • 7.1 心跳检测
    • 7.2 消息重试机制
  • 8. 注意事项
  • 9. 总结
  • 参考资料

1. 什么是WebSocket

WebSocket 是一种网络通信协议,提供全双工通信通道,使服务器可以主动向客户端推送数据。与传统的 HTTP 请求-响应模式不同,WebSocket 在建立连接后,允许服务器和客户端之间进行双向实时通信。

主要特点:

  • 建立在 TCP 协议之上
  • 与 HTTP 协议有良好的兼容性
  • 数据格式轻量,性能开销小
  • 可以发送文本和二进制数据
  • 没有同源限制,客户端可以与任意服务器通信

2. 环境准备

2.1 项目依赖

首先在pom.xml中添加必要的依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.5</version>
</parent>

<dependencies>
    <!-- WebSocket依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    
    <!-- Web依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Lombok依赖(可选) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

image-20241215200948577

3. WebSocket配置

3.1 WebSocket配置类

创建 WebSocket 配置类,启用 WebSocket 功能并注册端点:

package com.coderjia.boot3websocket.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

/**
 * @author CoderJia
 * @create 2024/12/15 下午 08:11
 * @Description
 **/
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler(), "/websocket")
                .setAllowedOrigins("*"); // 允许跨域访问
    }

    @Bean
    public WebSocketHandler webSocketHandler() {
        // 使用自定义的WebSocket处理器
        return new CustomWebSocketHandler();
    }
}

3.2 自定义WebSocket处理器

创建自定义的 WebSocket 处理器,处理消息收发:

package com.coderjia.boot3websocket.config;

import lombok.extern.slf4j.Slf4j;
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.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author CoderJia
 * @create 2024/12/15 下午 08:21
 * @Description
 **/
@Component
@Slf4j
public class CustomWebSocketHandler extends TextWebSocketHandler {

    // 用于存储WebSocket会话
    private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String sessionId = session.getId();
        sessions.put(sessionId, session);
        log.info("WebSocket连接建立成功:{}", sessionId);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        log.info("收到消息:{}", payload);

        // 发送回复消息
        String replyMessage = "服务器收到消息:" + payload;
        session.sendMessage(new TextMessage(replyMessage));
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String sessionId = session.getId();
        sessions.remove(sessionId);
        log.info("WebSocket连接关闭:{}", sessionId);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("WebSocket传输错误", exception);
    }

    // 广播消息给所有连接的客户端
    public void broadcastMessage(String message) {
        sessions.values().forEach(session -> {
            try {
                session.sendMessage(new TextMessage(message));
            } catch (IOException e) {
                log.error("广播消息失败", e);
            }
        });
    }
}

4. 控制器

创建 REST 控制器,用于测试消息广播:

@RestController
@RequestMapping("/api/websocket")
public class WebSocketController {
    
    private final CustomWebSocketHandler webSocketHandler;
    
    public WebSocketController(CustomWebSocketHandler webSocketHandler) {
        this.webSocketHandler = webSocketHandler;
    }
    
    @PostMapping("/broadcast")
    public ResponseEntity<String> broadcastMessage(@RequestBody String message) {
        webSocketHandler.broadcastMessage(message);
        return ResponseEntity.ok("消息广播成功");
    }
}

5. 前端实现

5.1 HTML页面

<!DOCTYPE html>
<html lang="en">
<head>
    <title>WebSocket测试</title>
</head>
<body>
    <div>
        <h2>WebSocket测试页面</h2>
        <div>
            <input type="text" id="messageInput" placeholder="输入消息">
            <button onclick="sendMessage()">发送</button>
        </div>
        <div id="messages" style="margin-top: 20px;"></div>
    </div>
    
    <script>
        let ws = null;
        
        function connect() {
            ws = new WebSocket('ws://localhost:8080/websocket');
            
            ws.onopen = function() {
                console.log('WebSocket连接已建立');
                appendMessage('系统消息:连接已建立');
            };
            
            ws.onmessage = function(event) {
                appendMessage('收到消息:' + event.data);
            };
            
            ws.onclose = function() {
                console.log('WebSocket连接已关闭');
                appendMessage('系统消息:连接已关闭');
            };
            
            ws.onerror = function(error) {
                console.error('WebSocket错误:', error);
                appendMessage('系统消息:连接发生错误');
            };
        }
        
        function sendMessage() {
            const messageInput = document.getElementById('messageInput');
            const message = messageInput.value;
            
            if (ws && message) {
                ws.send(message);
                appendMessage('发送消息:' + message);
                messageInput.value = '';
            }
        }
        
        function appendMessage(message) {
            const messagesDiv = document.getElementById('messages');
            const messageElement = document.createElement('div');
            messageElement.textContent = message;
            messagesDiv.appendChild(messageElement);
        }
        
        // 页面加载完成后连接WebSocket
        window.onload = connect;
    </script>
</body>
</html>

6. 测试WebSocket功能

  1. 启动 SpringBoot 应用

  2. 打开多个浏览器窗口访问 HTML 页面

  3. 在任意窗口发送消息,观察其他窗口是否收到消息

  4. 使用 POST 请求测试广播功能:

    curl -X POST http://localhost:8080/api/websocket/broadcast
    -H “Content-Type: text/plain”
    -d “这是一条广播消息”

连接

HTML页面

测接口

广播

7. 进阶功能

7.1 心跳检测

为了保持WebSocket连接的稳定性,可以实现心跳机制:

    @Scheduled(fixedRate = 10000) // 每10秒发送一次心跳,需要启动类或配置类上添加@EnableScheduling
    public void sendHeartbeat() {
        String heartbeat = "heartbeat";
        sessions.values().forEach(session -> {
            try {
                session.sendMessage(new TextMessage(heartbeat));
            } catch (IOException e) {
                log.error("发送心跳消息失败", e);
            }
        });
    }

心跳

7.2 消息重试机制

当消息发送失败时,实现重试机制:

public void sendMessageWithRetry(WebSocketSession session, String message, int maxRetries) {
    int retryCount = 0;
    while (retryCount < maxRetries) {
        try {
            session.sendMessage(new TextMessage(message));
            return;
        } catch (IOException e) {
            retryCount++;
            log.error("消息发送失败,尝试重试 {}/{}", retryCount, maxRetries);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    log.error("消息发送失败,达到最大重试次数");
}

8. 注意事项

  1. 连接管理

    • 及时清理断开的连接
    • 实现最大连接数限制
    • 考虑使用连接池管理WebSocket连接
  2. 安全性

    • 实现用户认证
    • 添加消息加密
    • 设置适当的跨域策略
  3. 性能优化

    • 使用消息队列处理大量消息
    • 实现消息压缩
    • 控制消息大小
  4. 错误处理

    • 完善异常处理机制
    • 实现日志记录
    • 添加监控告警

9. 总结

SpringBoot 3 整合 WebSocket 提供了一种高效的实时通信解决方案。通过本文的配置和示例,你可以快速实现:

  • WebSocket服务器端配置
  • 客户端连接管理
  • 消息收发处理
  • 广播功能
  • 心跳检测
  • 错误处理

这些功能可以作为构建实时应用的基础,如在线聊天、实时数据推送、游戏等场景。根据具体需求,你可以在此基础上扩展更多功能。

参考资料

  • Spring WebSocket文档
  • WebSocket协议规范
  • Spring Boot文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/955296.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

技术晋升读书笔记—办事的艺术

作为一名程序员&#xff0c;沟通能力对于我们这一行来说并不是强项。大多数程序员与电脑打交道的时间远远多于与人交流&#xff0c;特别工作一天有可能全程在与电脑打交道&#xff0c;因此沟通技巧的提升往往被忽视。然而&#xff0c;随着职业发展的推进&#xff0c;尤其在国内…

警惕IDEA 2024版重大Bug问题:LomBok失效、Gradle冲突、Spring Boot启动错误

一直以来我认为工具类的软件是越新越好&#xff0c;因为工具代表着一定的先进性&#xff1b;但是IDEA 2024好好的给我上了一课&#xff0c;比如lombok 不起作用、比如Spring Boot 3.4.x 启动报错、再比如MyBatis log plus冲突、再比如Gradle插件冲突. 一、Lombok 失效问题 请不…

01、flink的原理和安装部署

flink中主要有两个进程&#xff0c;分别是JobMManager和TaskManager&#xff0c;当然了根据flink的部署和运行环境不同&#xff0c;会有一些不同&#xff0c;但是主要的功能是类似的&#xff0c;下面我会讲下聊下&#xff0c;公司用的多的部署方式&#xff0c;基于yarn集群的部…

Vue2+OpenLayers实现车辆开始、暂停、重置行驶轨迹动画(提供Gitee源码)

前言&#xff1a;根据经纬度信息绘制一个完整的行驶路线&#xff0c;车辆根据绘制好的路线从开始点位行驶到结束点位&#xff0c;可以通过开始、暂停、重置按钮控制车辆状态。 目录 一、案例截图 二、安装OpenLayers库 三、​安装Element-UI ​ 四、代码实现 4.1、初始化…

两个React项目部署在同一个域名,一个主地址,一个子地址,二级白屏等问题

主域名配置的那个项目正常配置就可以了&#xff0c;但是对于子地址的项目&#xff0c;需要做很多的配置的。 注意 子地址的那个项目在配置中需要配置为子地址&#xff1a; base: /subpk 在vite.config.ts中修改&#xff1a; 如果这里没有配置正确&#xff0c;会导致白屏或者…

管理口令安全和资源(二)

DBMS_METADATA DBMS_METADATA 是 Oracle 数据库中的一个包&#xff0c;它提供了用于管理数据库元数据的工具和过程。元数据是关于数据的数据&#xff0c;它描述了数据库的结构&#xff0c;包括表、视图、索引、存储过程、用户和其他数据库对象的信息。DBMS_METADATA 包允许用户…

【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)

&#xff1a; 羑悻的小杀马特.-CSDN博客羑悻的小杀马特.擅长C/C题海汇总,AI学习,c的不归之路,等方面的知识,羑悻的小杀马特.关注算法,c,c语言,青少年编程领域.https://blog.csdn.net/2401_82648291?spm1010.2135.3001.5343 在本篇文章中&#xff0c;博主将带大家去学习所谓的…

Kotlin Bytedeco OpenCV 图像图像57 图像ROI

Kotlin Bytedeco OpenCV 图像图像57 图像ROI 1 添加依赖2 测试代码3 测试结果 1 添加依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://maven.apache.o…

Linux手写FrameBuffer任意引脚驱动spi屏幕

一、硬件设备 开发板&#xff1a;香橙派 5Plus&#xff0c;cpu&#xff1a;RK3588&#xff0c;带有 40pin 外接引脚。 屏幕&#xff1a;SPI 协议 0.96 寸 OLED。 二、需求 主要是想给板子增加一个可视化的监视器&#xff0c;并且主页面可调。 平时跑个模型或者服务&#xff0c;…

【Linux】gdb_进程概念

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

【k8s面试题2025】3、练气中期

体内灵气的量和纯度在逐渐增加。 文章目录 在 Kubernetes 中自定义 Service端口报错常用控制器Kubernetes 中拉伸收缩副本失效设置节点容忍异常时间Deployment 控制器的升级和回滚日志收集资源监控监控 Docker将 Master 节点设置为可调度 在 Kubernetes 中自定义 Service端口报…

飞牛 使用docker部署Watchtower 自动更新 Docker 容器

Watchtower是一款开源的Docker容器管理工具&#xff0c;其主要功能在于自动更新运行中的Docker容器 Watchtower 支持以下功能&#xff1a; 自动拉取镜像并更新容器。 配置邮件通知。 定时执行容器更新任务。 compose搭建Watchtower 1、新建文件夹 先在任意位置创建一个 w…

使用NetLimiter限制指定应用的网速

NetLimiter是一款用于网络流量监控和控制的软件&#xff0c;适合需要管理网络带宽的用户。在项目测试中&#xff0c;它帮助我对特定应用进行限速&#xff0c;合理分配网络资源&#xff0c;避免了因单一应用过度占用带宽而引发的网络问题。通过NetLimiter&#xff0c;我可以为每…

Python根据图片生成学生excel成绩表

学习笔记&#xff1a; 上完整代码 import os import re from openpyxl import Workbook, load_workbook from openpyxl.drawing.image import Image as ExcelImage from PIL import Image as PilImage# 定义图片路径和Excel文件路径 image_dir ./resources/stupics # 图片所…

56_多级缓存实现

1.查询Tomcat 拿到商品id后,本应去缓存中查询商品信息,不过目前我们还未建立Nginx、Redis缓存。因此,这里我们先根据商品id去Tomcat查询商品信息。此时商品查询功能的架构如下图所示。 需要注意的是,我们的OpenResty是在虚拟机,Tomcat是在macOS系统(或Windows系统)上,…

【Linux系统】Ext系列磁盘文件系统二:引入文件系统(续篇)

inode 和 block 的映射 该博文中有详细解释&#xff1a;【Linux系统】inode 和 block 的映射原理 目录与文件名 这里有几个问题&#xff1a; 问题一&#xff1a; 我们访问文件&#xff0c;都是用的文件名&#xff0c;没用过 inode 号啊&#xff1f; 之前总是说可以通过一个…

2024年博客之星年度评选—创作影响力评审入围名单公布

2024年博客之星活动地址https://www.csdn.net/blogstar2024 TOP 300 榜单排名 用户昵称博客主页 身份 认证 评分 原创 博文 评分 平均 质量分评分 互动数据评分 总分排名三掌柜666三掌柜666-CSDN博客1001002001005001wkd_007wkd_007-CSDN博客1001002001005002栗筝ihttps:/…

基于高光谱数据的叶片水分估测方法研究 【Matlab Python Origin】

相关代码和结果在这里&#xff1a;基于高光谱数据的叶片水分估测方法研究 【Matlab Python Origin】文章中的代码和结果 第1章 研究内容和技术路线 1.1 研究内容 在本文研究中&#xff0c;我们致力于充分利用LOPEX’93数据集&#xff0c;并通过深入分析高光谱数据&#xff0c;…

windows下安装并使用node.js

一、下载Node.js 选择对应你系统的Node.js版本下载 Node.js官网下载地址 Node.js中文网下载地址??? 这里我选择的是Windows64位系统的Node.js20.18.0&#xff08;LTS长期支持版本&#xff09;版本的.msi安装包程序 官网下载&#xff1a; 中文网下载&#xff1a; 二、安…

西门子PLC读取梅安森风速传感器数据

西门子PLC读取梅安森风速传感器数据 读取数据前期准备&#xff1a;西门子PLC读取数据 设备型号为&#xff1a;GFY15 到货开盒的设备有&#xff1a;风速传感器、485线及设置遥控器 读取数据前期准备&#xff1a; 将设备的私有485协议改为modbus公有协议 刚上电的轮询显示时间同时…