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

Java21 + SpringBoot3集成WebSocket

文章目录

    • 前言
    • 相关技术简介
      • 什么是WebSocket
      • WebSocket的原理
      • WebSocket与HTTP协议的关系
      • WebSocket优点
      • WebSocket应用场景
    • 实现方式
      • 1. 添加maven依赖
      • 2. 添加WebSocket配置类,定义ServerEndpointExporter Bean
      • 3. 定义WebSocket Endpoint
      • 4. 前端创建WebSocket对象
    • 总结

前言

近日心血来潮想做一个开源项目,目标是做一款可以适配多端、功能完备的模板工程,包含后台管理系统和前台系统,开发者基于此项目进行裁剪和扩展来完成自己的功能开发。
本项目为前后端分离开发,后端基于Java21SpringBoot3开发,前端提供了vue、angular、react、uniapp、微信小程序等多种脚手架工程。
本文主要介绍项目中如何集成WebSocket实现服务器端与客户端的双向通信。

相关技术简介

什么是WebSocket

WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。
http是一种无状态,无连接,单向的应用层协议,它采用了请求/响应模型,通信请求只能由客户端发起,服务端对请求做出应答处理。这样的弊端显然是很大的,只要服务端状态连续变化,客户端就必须实时响应,都是通过javascript与ajax进行轮询,这样显然是非常麻烦的,同时轮询的效率低,非常的浪费资源(http一直打开,一直重复的连接)。
于是就有了WebSocket,它是一种全面双工通讯的网络技术,任意一方都可以建立连接将数据推向另一方,WebSocket只需要建立一次连接,就可以一直保持。

WebSocket的原理

  1. WebSocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方便它们之间的通信
  2. 在WebSocket出现之前,web交互一般是基于http协议的短连接或者长连接
  3. WebSocket是一种全新的协议,不属于http无状态协议,协议名为"ws"

WebSocket与HTTP协议的关系

WebSocket优点

  1. 减少请求费时费资源:是真正的全双工方式,建立连接后,服务器与客户端时完全对等的,可以相互请求,减少了不必要的网络请求时间损耗和网络流量;
  2. 更持久:WebSocket协议通过第一个request建立TCP连接后,只要不主动关闭,就能一直保持连接状态交换数据;
  3. 服务端可以主动向客户端发送消息;

WebSocket应用场景

社交聊天、弹幕、多玩家游戏、协同编辑、股票基金实时报价、体育实况更新、视频会议/聊天、基于位置的应用、在线教育、智能家居等需要高实时的场景都可以使用WebSocket技术实现。

实现方式

本项目后端基于Java 21SpringBoot3开发,前端基于Vue3实现。

1. 添加maven依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>3.2.0</version>
</dependency>

2. 添加WebSocket配置类,定义ServerEndpointExporter Bean

@Configuration
@EnableWebSocket
public class WebSocketConfig {/*** 注入ServerEndpointExporter,* 这个bean会自动注册使用了@ServerEndpoint注解声明的WebSocket Endpoint*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

3. 定义WebSocket Endpoint

/*** 消息提醒计数WebSocket*/
@ServerEndpoint("/ws/test/{userId}")
@Component
@Slf4j
public class TestWebSocketServer {/*** 与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/*** 用户ID*/private Long userId;/*** concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。* 虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。*/private static final CopyOnWriteArraySet<MessageCountWebSocketServer> webSockets = new CopyOnWriteArraySet<>();/*** 用来存在线连接用户信息*/private static final ConcurrentHashMap<Long, Session> sessionPool = new ConcurrentHashMap<>();/*** 链接成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam(value = "userId") Long userId) {this.session = session;this.userId = userId;webSockets.add(this);sessionPool.put(userId, session);log.info("建立与UserID:{}的消息提醒计数连接", userId);}/*** 链接关闭调用的方法*/@OnClosepublic void onClose() {webSockets.remove(this);sessionPool.remove(this.userId);log.info("关闭与UserID:{}的消息提醒计数连接", userId);}/*** 收到客户端消息后调用的方法*/@OnMessagepublic void onMessage(String message) {log.info("接收到UserID:{}的消息{}", userId, message);}/*** 发送错误时的处理*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发送到UserID:{}的消息传输失败", userId, error);}/*** 广播消息** @param message*/public void sendAllMessage(String message) {for (MessageCountWebSocketServer socketServer : webSockets) {if (socketServer.session.isOpen()) {socketServer.session.getAsyncRemote().sendText(message);}}}/*** 单人单播消息** @param userId* @param message*/public void sendOneMessage(Long userId, String message) {Session session = sessionPool.get(userId);if (session != null && session.isOpen()) {session.getAsyncRemote().sendText(message);}}/*** 多人单播消息** @param userIds* @param message*/public void sendMoreMessage(Long[] userIds, String message) {for (Long userId : userIds) {Session session = sessionPool.get(userId);if (session != null && session.isOpen()) {session.getAsyncRemote().sendText(message);}}}
}

4. 前端创建WebSocket对象

以下代码基于Vue3的组合式API编写。

<script setup>import { onMounted, onBeforeMount } from 'vue';/*** @type {WebSocket}*/let websocket = null;onMounted(async () => {initTestWebSocket();});onBeforeMount(async()=>{websocket && websocket.close();});const initTestWebSocket = async () => {const userId = '当前用户ID';console.log("尝试建立websockect连接");websocket = new WebSocket(`/ws/test/${userId}`);websocket.onopen = function (event) {console.log("建立连接");}websocket.onclose = function (event) {console.log('连接关闭')//尝试重连websocketreconnectMessageWebSocket();}//建立通信后,监听到后端的数据传递websocket.onmessage = function (event) {// 打印后端传来的数据console.log(event.data);// 调用WebSocket对象的send方法可向后端发送数据// websocket.send("test data");}websocket.onerror = function () {console.log("数据发送失败");}// 窗口关闭前关闭WebSocket连接window.onbeforeunload = function () {websocket.close();}};// 重连const reconnectMessageWebSocket = () => {console.log("正在重连");// 进行重连setTimeout(() => {initTestWebSocket();}, 1000);}
</script>

总结

本文介绍了WebSocket的相关概念,以及如何基于Java21、SpringBoot3和Vue3使用WebSocket,在使用过程中也遇到了一些问题。

  • 执行mvn packagemvn test命令时报错

    请参阅 Java21 + SpringBoot3使用spring-websocket时执行mvn package报错。

  • 如果后端使用Spring SecurityShiroSa-Token等技术,需要考虑使用@ServerEndpoint注解所配置url的权限控制问题。

我也会及时的更新后续实践中所遇到的问题,希望与诸位看官一起进步。
如有错误,还望批评指正。

相关文章:

Java21 + SpringBoot3集成WebSocket

文章目录 前言相关技术简介什么是WebSocketWebSocket的原理WebSocket与HTTP协议的关系WebSocket优点WebSocket应用场景 实现方式1. 添加maven依赖2. 添加WebSocket配置类&#xff0c;定义ServerEndpointExporter Bean3. 定义WebSocket Endpoint4. 前端创建WebSocket对象 总结 前…...

鲸鱼优化算法WOA改进预告

鲸鱼优化算法&#xff08;Whale Optimization Algorithm&#xff0c;WOA&#xff09;是一种基于自然界中鲸鱼群体行为的启发式优化算法。这个算法模拟了鲸鱼的觅食行为和社会行为&#xff0c;通过模拟这些行为来解决优化问题。 以下是鲸鱼优化算法的一些关键特点和步骤&#x…...

Nightingale 夜莺监控系统 - 告警篇(3)

Author&#xff1a;rab 官方文档&#xff1a;https://flashcat.cloud/docs/content/flashcat-monitor/nightingale-v6/usage/alert/alert-rule/ 目录 前言一、配置1.1 创建钉钉机器人1.2 n9e 创建通知用户1.3 n9e 创建团队&#xff08;组&#xff09;1.4 将通知用户添加团队1.…...

【LeetCode2696】删除子串后的字符串最小长度

1、题目描述 【题目链接】 标签&#xff1a;栈 、字符串、模拟 难度&#xff1a;简单 给你一个仅由 大写 英文字符组成的字符串 s 。 你可以对此字符串执行一些操作&#xff0c;在每一步操作中&#xff0c;你可以从 s 中删除 任一个 “AB” 或 “CD” 子字符串。 通过执行操作…...

VMware安装CentOS7虚拟机

VMware 安装 获取 VMware 安装包 下载地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1ELR5NZa7rO6YVplZ1IUigw?pwdplz3 提取码&#xff1a;plz3 包括&#xff1a;当然&#xff0c;也可以自己去别的地方下载&#xff0c;WMware 版本都差不多&#xff0c;现在用的比…...

Linux第22步_安装CH340驱动和串口终端软件MobaXterm

开发板输出信息通常是采用串口&#xff0c;而计算机通常是USB接口&#xff0c;为了让他们之间能够交换数据&#xff0c;我们通常采用USB转串口的转换器来实现。目前市场上的串口转换器大多是采用CH340芯片来实现的&#xff0c;因此我们需要在计算中安装一个CH340驱动程序&#…...

Elasticsearch 地理空间搜索 - 远超 OpenSearch

作者&#xff1a;来自 Elastic Nathan_Reese 2021 年&#xff0c;OpenSearch 和 OpenSearch Dashboards 开始作为 Elasticsearch 和 Kibana 的分支。 尽管 OpenSearch 和 OpenSearch Dashboards 具有相似的血统&#xff0c;但它们不提供相同的功能。 在分叉时&#xff0c;只能克…...

USB micro输入口中三个问题详解——差分信号、自恢复保险丝SMD1210P050TF、电容滤波

前言&#xff1a;本文对USB micro输入口中遇见的三个问题进行详解&#xff1a;差分信号、自恢复保险丝SMD1210P050TF、电容滤波 目录&#xff1a; 差分信号 自恢复保险丝SMD1210P050TF 电容滤波 如下图&#xff0c;USB为U-F-M5DD-Y-1型号&#xff08;9个引脚&#xff0c;除…...

mysql原理--undo日志1

1.事务回滚的需求 我们说过 事务 需要保证 原子性 &#xff0c;也就是事务中的操作要么全部完成&#xff0c;要么什么也不做。但是偏偏有时候事务执行到一半会出现一些情况&#xff0c;比如&#xff1a; (1). 事务执行过程中可能遇到各种错误&#xff0c;比如服务器本身的错误&…...

Zookeeper系列(一)集群搭建(非容器)

系列文章 Zookeeper系列&#xff08;一&#xff09;集群搭建&#xff08;非容器&#xff09; 目录 前言 下载 搭建 Data目录 Conf目录 集群复制和修改 启动 配置示例 测试 总结 前言 Zookeeper是一个开源的分布式协调服务&#xff0c;其设计目标是将那些复杂的且容易出错的分…...

【高等数学之泰勒公式】

一、从零开始 1.1、泰勒中值定理1 什么是泰勒公式?我们先看看权威解读: 那么我们从古至今到底是如何创造出泰勒公式的呢? 由上图可知&#xff0c;任一无穷小数均可以表示成用一系列数字的求和而得出的结果&#xff0c;我们称之为“无穷算法”。 那么同理我们想对任一曲线来…...

奇异值分解在图形压缩中的应用

奇异值分解在图形压缩中的应用 在研究奇异值分解的工程应用之前&#xff0c;我们得明白什么是奇异值&#xff1f;什么是奇异向量&#xff1f; 奇异值与奇异向量 概念&#xff1a;奇异值描述了矩阵在一组特定向量上的行为&#xff0c;奇异向量描述了其最大的作用方向。 奇异值…...

C++深入学习之STL:1、容器部分

标准模板库STL的组成 主要由六大基本组件组成&#xff1a;容器、迭代器、算法、适配器、函数对象(仿函数)以及空间配置器。 容器&#xff1a;就是用来存数据的&#xff0c;也称为数据结构。 本文要详述的是容器主要如下&#xff1a; 序列式容器&#xff1a;vector、list 关联…...

Javascript——vue下载blob文档流

<el-table-column label"操作" fixed"right" width"150" showOverflowTooltip><template slot-scope"scope"><el-button type"text" v-has"stbsd-gjcx-down" class"edit-button" click&…...

C# 的SequenceEqual

SequenceEqual 是 LINQ 扩展方法之一&#xff0c;用于比较两个序列&#xff08;如数组、列表等&#xff09;的元素是否相等。 该方法的详细定义如下&#xff1a; public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TS…...

第九部分 使用函数 (一)

目录 一、简介 二、函数的调用语法 一、简介 在 Makefile 中可以使用函数来处理变量&#xff0c;从而让我们的命令或是规则更为的灵活和具 有智能。make 所支持的函数也不算很多&#xff0c;不过已经足够我们的操作了。函数调用后&#xff0c;函数 的返回值可以当做变量来使用…...

【JUC进阶】14. TransmittableThreadLocal

目录 1、前言 2、TransmittableThreadLocal 2.1、使用场景 2.2、基本使用 3、实现原理 4、小结 1、前言 书接上回《【JUC进阶】13. InheritableThreadLocal》&#xff0c;提到了InheritableThreadLocal虽然能进行父子线程的值传递&#xff0c;但是如果在线程池中&#x…...

基于C++的ORM框架sqlpp11入门介绍(附MySQL运行实例)

基本介绍 sqlpp11 是 C 的类型安全的 SQL 模版库。 Sqlpp11的官方下载地址是&#xff0c; GitHub - rbock/sqlpp11: A type safe SQL template library for C 在这里&#xff0c;可以找到官方的详细介绍文档&#xff0c; https://github.com/rbock/sqlpp11/tree/main/docs…...

对写文章的想法

一些思考 思考初心现在错觉想说的话 最后 思考 在CSDN里面写文章已经快半年了啊&#xff0c;虽然更得不多&#xff0c;但每一篇都花费很多时间&#xff0c;写的时候能帮自己查漏补缺&#xff0c;这边找找资料补充一下&#xff0c;都能去拓展自己的知识面&#xff0c;让自己的文…...

Istio安装和基础原理

1、Istio简介 Istio 是一个开源服务网格&#xff0c;它透明地分层到现有的分布式应用程序上。 Istio 强大的特性提供了一种统一和更有效的方式来保护、连接和监视服务。 Istio 是实现负载平衡、服务到服务身份验证和监视的路径——只需要很少或不需要更改服务代码。它强大的控…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...