Spring Boot 实现 WebSocket(注解方式)

本文介绍如何使用 Spring Boot 的注解方式实现一个简单的 WebSocket 服务,支持客户端与服务器之间进行实时通信。

1. 引入依赖

在 pom.xml 文件中添加 WebSocket 相关依赖。

<dependencies>
    <!-- Spring Boot WebSocket 支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
</dependencies>

2.创建 WebSocket 服务类

使用 @ServerEndpoint 注解定义 WebSocket 的处理逻辑。下面是一个简单的示例类,它处理客户端连接、消息接收和消息发送。

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@ServerEndpoint("/ws")
public class WebSocketServer {

    // 用于存储所有的会话
    private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
    private Session session;

    // 连接建立成功调用的方法
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);
        System.out.println("新连接加入: " + session.getId());
    }

    // 连接关闭时调用的方法
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        System.out.println("连接关闭: " + session.getId());
    }

    // 收到客户端消息时调用的方法
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("收到消息: " + message);
        broadcast("服务器: " + message);  // 广播消息给所有客户端
    }

    // 发送消息给客户端
    private void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    // 广播消息给所有客户端
    private static void broadcast(String message) {
        for (WebSocketServer webSocket : webSocketSet) {
            try {
                webSocket.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3. WebSocket 配置类

在 Spring Boot 中,需要通过配置类注册 WebSocket 端点。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {

    // 自动注册使用 @ServerEndpoint 注解声明的 WebSocket 端点
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

4. 编写前端客户端代码

为了测试 WebSocket 服务,可以通过一个简单的 HTML 文件与 WebSocket 服务进行交互。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket Test</title>
</head>
<body>
    <h2>WebSocket 测试</h2>
    <input id="messageInput" type="text" placeholder="输入消息">
    <button onclick="sendMessage()">发送</button>

    <ul id="messages"></ul>

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

        socket.onmessage = function(event) {
            let messages = document.getElementById("messages");
            let messageItem = document.createElement("li");
            messageItem.textContent = event.data;
            messages.appendChild(messageItem);
        };

        function sendMessage() {
            let input = document.getElementById("messageInput");
            let message = input.value;
            socket.send(message);
            input.value = '';
        }
    </script>
</body>
</html>

5. 启动应用程序

完成以上步骤后,启动 Spring Boot 应用程序。WebSocket 服务将会运行在 ws://localhost:8080/ws,前端可以通过该地址与服务器进行实时通信。

6. 测试 WebSocket

启动应用程序后,打开前端 HTML 页面。
输入消息并点击发送按钮,服务器会收到消息并将其广播给所有连接的客户端。
在浏览器开发工具中也可以观察到 WebSocket 的实时消息交互。

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

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

相关文章

【K8S系列】Kubernetes node节点NotReady问题及解决方案详解【已解决】

Kubernetes 集群中的每个节点都是运行容器化应用的基础。当节点状态显示为 NotReady 时,意味着该节点无法正常工作,这可能会导致 Pod 无法调度,从而影响整个应用的可用性。本文将深入分析节点不健康的各种原因、详细的排查步骤以及有效的解决方案。 一、节点不健康的原因 节…

Leetcode—1226. 哲学家进餐【中等】(多线程)

2024每日刷题&#xff08;185&#xff09; Leetcode—1226. 哲学家进餐 C实现代码 class DiningPhilosophers { public:mutex mx;DiningPhilosophers() {}void wantsToEat(int philosopher,function<void()> pickLeftFork,function<void()> pickRightFork,functi…

双十一开启极速达夜派;黑神话获泰国年度最佳游戏;AI 模型可帮助识别 17000 多种疾病的候选药物....| 网易数智日报

双 11 菜鸟在北京、上海、广州、杭州等城市开启「预售极速达夜派」服务 10 月 21 日&#xff0c;菜鸟在北京、上海、广州、杭州等城市开启「预售极速达夜派」服务&#xff0c;批量大促包裹实现小时级送达。 据介绍&#xff0c;在消费者支付尾款前&#xff0c;菜鸟供应链就已经…

闯关leetcode——190. Reverse Bits

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/reverse-bits/description/ 内容 Reverse bits of a given 32 bits unsigned integer. Note: Note that in some languages, such as Java, there is no unsigned integer type. In this case, …

使用excel.js(layui-excel)进行layui多级表头导出,根据单元格内容设置背景颜色,并将导出函数添加到toolbar

本段是菜狗子的碎碎念&#xff0c;解决办法请直接从第二段开始看。layui多级表头的导出&#xff0c;弄了两天才搞定&#xff0c;中途一度想放弃&#xff0c;还好坚持下来了。一开始用的是layui的toolbar里自带的那个导出&#xff0c;但是多级表头没有正常导出&#xff0c;单元格…

ORACLE SELECT INTO 赋值为空,抛出 NO DATA FOUND 异常

例子&#xff1a; DECLARE ORDER_NUM VARCHAR2(20); BEGIN SELECT S.ORDER_NUM INTO ORDER_NUM FROM SALES_ORDER S WHERE S.ID122344; DBMS_OUTPUT.PUT_LINE(单号: || ORDER_NUM); END; 在查询结果为空的情况下&#xff0c;以上代码会报错&#xff1a;未找到任何数据 解决方…

深度学习——循环神经网络RNN知识点小结(全)

前置知识: 序列模型--输出/输入中包含有序列数据的模型 特点: 1.输入/输出元素之间具有顺序关系, 不同顺序得到的结果不同 2.输入输出不定长, 比如问答系统, 聊天机器人 DL--RNN 小名:循环神经网络 外国小名: sequence model 定义: 专门设计用来处理序列数据的神经网络 应用: …

2024临床常用的营养评价量表汇总!

临床常用量表来评估患者的营养状况、营养摄入风险&#xff0c;常笑医学整理了5个临床常用的营养评价量表&#xff0c;包括SGA营养评价表、老年营养风险指数、营养风险筛查评分简表、简易营养评价精法量表、微型营养评估量表等。这些量表在常笑医学网均支持在线评估、下载和创建…

(四)问题记录:matlab中spatial contact force模块下关于stiffness(刚度)的设定

最近在搞一阶倒立摆&#xff0c;在matlab仿真时遇到这样的问题&#xff1a;stiffness设置为10e5就会发生碰撞后穿透&#xff0c;&#xff08;四个spatial contact force模块是分别连接小车四个轮子和地面的&#xff09; 而设置成10e6就不会有问题&#xff0c; 由于本人也是第一…

cefsharp 88.2.90.0(Chromium 88.0.4324.182)支持H264视频播放-PDF预览 老版本回顾系列体验-100以下版本

一、关于此版本 Cef 88.2.9/CefSharp 88.2.90/Chromium 88.0.4324.182/支持H264/支持PDF预览 支持PDF预览和H264推荐版本 63/79/84/88/100/111/125 框架:NET4.5.2,X86 注意运行环境支持变化1.1 扩展(关于DPI黑边框问题解决) this.AutoScaleMode = AutoScaleMode.Dpi;

QT 机器视觉 1.相机类型

本专栏从实际需求场景出发详细还原、分别介绍大型工业化场景、专业实验室场景、自动化生产线场景、各种视觉检测物体场景介绍本专栏应用场景 更适合涉及到视觉相关工作者、包括但不限于一线操作人员、现场实施人员、项目相关维护人员&#xff0c;希望了解2D、3D相机视觉相关操作…

动态链接过程分析

目录 一、前言二、示例程序三、动态库的加载过程1、动态链接器加载动态库2、动态库的加载地址 四、符号重定位1、全局符号表2、全局偏移表 GOT3、liba.so 动态库文件的布局4、liba.so 动态库的虚拟地址5、GOT 表的内部结构6、反汇编 liba.so 代码 五、补充1、延迟绑定 plt 上文…

机器学习实战:从数据预处理到模型评估的完整案例

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

面试总结一

面试总结 1、自我介绍一下自己2.面试11、css常用布局有哪些2、css常用的属性3.js原型链4、开发中遇到的技术难点5、闭包6、ts了解什么呢7.git都用什么命令8、vue怎么打包9.vue启动一个项目需要什么10、vue怎么创建一个项目 2.面试21.vue2和vue3有什么区别2.复杂组件的封装&…

《Java与API的浪漫邂逅:一键获取商品详情》

亲爱的Java爱好者们&#xff0c;你是否曾在夜深人静时&#xff0c;对着电脑屏幕发呆&#xff0c;思考如何用你的代码去征服那些遥远的API数据&#xff1f;你是否梦想着&#xff0c;只需轻轻一点&#xff0c;就能让商品详情如魔法般出现在你的眼前&#xff1f;今天&#xff0c;我…

数据结构与算法:贪心算法与应用场景

目录 11.1 贪心算法的原理 11.2 经典贪心问题 11.3 贪心算法在图中的应用 11.4 贪心算法的优化与扩展 总结 数据结构与算法&#xff1a;贪心算法与应用场景 贪心算法是一种通过选择当前最佳解来构造整体最优解的算法策略。贪心算法在很多实际问题中都取得了良好的效果&am…

Struts2标签库全解密:打造高效、动态的Web界面

文章目录 Struts2的标签通用(Generic)标签<s:property> 数据类标签<s:iterator>&#xff08;至关重要&#xff01;&#xff01;&#xff01;&#xff01;&#xff09;<s:if> <s:elseif> <s:else><s:a>超链接标签用户界面(UI)标签表单标签 …

【C++打怪之路Lv12】-- 模板进阶

#1024程序员节&#xff5c;征文# &#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您…

Java集合剖析4】LinkedList

目录 一、LinkedList的特有方法 二、LinkedList的底层数据结构 三、插入方法的具体实现 一、LinkedList的特有方法 LinkedList的底层是双向链表&#xff0c;它提供了操作首尾结点的方法。 二、LinkedList的底层数据结构 LinkedList的底层数据结构是一个双向链表&#xff0c;体现…

LeetCode 0908.最小差值 I:思维(遍历)

【LetMeFly】908.最小差值 I&#xff1a;思维&#xff08;遍历&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/smallest-range-i/ 给你一个整数数组 nums&#xff0c;和一个整数 k 。 在一个操作中&#xff0c;您可以选择 0 < i < nums.length 的…