Springboot2.7集成websocket及相关问题
1、集成websocket完整代码
导入maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
服务端代码
(1)注入bean
@Configuration
@EnableWebSocket
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
(2)服务端开放的服务及其业务逻辑
@Slf4j
@Component
@ServerEndpoint("/testcase/page/{clientId}")
//@Lazy
public class WsMessageService {//与某个客户端的连接会话private Session session;//存放每个客户端对应的WebSocket对象。private static Map<String, WsMessageService> webSocketsBeanMap = new ConcurrentHashMap<>();//每次连接都是一个新的会话对象,线程安全的String userId;//注入业务类。要注意setTestcaseService()的名称不能错,set后的字符串要和要注入的变量名一致。private static TestcaseService testcaseService;@Autowiredpublic void setTestcaseService(TestcaseService testcaseService) {WsMessageService.testcaseService= testcaseService;}//private TestcaseService testcaseService = SpringContextUtil.getBean(TestcaseService.class);@OnOpenpublic void onOpen(Session session, @PathParam(value = "clientId") String userId) {this.session = session;this.userId = userId;webSocketsBeanMap.put(userId, this);log.info("OnOpen连接成功,userId:{},当前在线人数:{}", userId, this.getOnLineCount());}@OnMessagepublic void onMessage(String message) throws IOException {Session session = webSocketsBeanMap.get(this.userId).session;if (session==null || !session.isOpen()) {return;}log.info("收到客户端的消息:" + message);//start业务Integer pageNum = null;Integer pageSize = null;String pid = null;String vid = null;if (session.getRequestParameterMap().get("pageNum")!= null) {pageNum = Integer.valueOf(session.getRequestParameterMap().get("pageNum").get(0));}if (session.getRequestParameterMap().get("pageNum")!= null) {pageSize = Integer.valueOf(session.getRequestParameterMap().get("pageSize").get(0));}if (session.getRequestParameterMap().get("pid")!= null) {pid = session.getRequestParameterMap().get("pid").get(0);}if (session.getRequestParameterMap().get("vid")!= null) {vid = session.getRequestParameterMap().get("vid").get(0);}PageInfo<TestcasePageVO> pageInfo = testcaseService.findTestcaseByMultiCondition(pageNum, pageSize, pid, vid);//end业务try {JSONObject object = new JSONObject();object.put("data", pageInfo);object.put("code", 200);object.put("message", "SUCCESS");this.session.getBasicRemote().sendText(String.valueOf(object.toString()));} catch (IOException e) {throw new RuntimeException(e);}}@OnClosepublic void onClose() throws IOException {log.info("会话关闭,关闭会话的用户Id为:{}", this.userId);webSocketsBeanMap.remove(this.userId);log.info("当前在线人数:{}", this.getOnLineCount());}@OnErrorpublic void onError(Session session, Throwable error) {log.error("连接错误:" + error.getMessage());error.printStackTrace();}private int getOnLineCount() {return webSocketsBeanMap.size();}
}
测试服务端的可用性。在浏览器的控制台输入以下代码可以测试。
function initWebSocket(wsUri) {var websocket = new WebSocket(wsUri);websocket.onopen = function(evt) {console.log('连接建立中... '+wsUri);};websocket.onclose = function(evt) {console.log('连接关闭中...', evt);};websocket.onmessage = function(evt) {console.log('收到来自服务端的消息:', evt.data);};websocket.onerror = function(evt) {console.log('发生错误...', evt);};return websocket;}var websocket = initWebSocket("ws://ip:port/testcase/page/123?pid=5922cc3d03f74012a7112c931c8497d7&vid=fc2d7a6049ff4c7bafc40bf659b4e903");var msg, i = 0;var loop = setInterval(function(){msg = "Hello " +(i++);if(websocket.readyState == WebSocket.OPEN) {websocket.send(msg);console.log('已发送消息:' +msg);} else{clearInterval(loop);console.log('连接已关闭');}}, 10000);
2、集成websocket另一种方法(用控制台测试时返回的数据会乱码)
代码找不到了。但那种方法有一个特征就是使用的注解比当前的方法少。
3、解决业务类注入不进去的问题(两种方法,推荐第一种)
(1)第一种:就是当前使用的注入方法。注意命名,否则不会注入成功
//注入业务类。要注意setTestcaseService()的名称不能错,set后的字符串要和要注入的变量名一致。private static TestcaseService testcaseService;@Autowiredpublic void setTestcaseService(TestcaseService testcaseService) {WsMessageService.testcaseService= testcaseService;}
(2)第二种:自己写一个SpringContextUtil工具类,协助注入
package cn.xxxxx.tmMaster.utils;import lombok.extern.slf4j.Slf4j;
import org.mybatis.logging.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import java.util.logging.Logger;@Slf4j
@Component
public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringContextUtil.applicationContext = applicationContext;}/*** 获取 applicationContext*/public static ApplicationContext getApplicationContext() {return applicationContext;}/*** 通过 name 获取 bean 对象*/public static Object getBean(String name) {return getApplicationContext().getBean(name);}/*** 通过 class 获取 bean 对象*/public static <T> T getBean(Class<T> clazz) {return getApplicationContext().getBean(clazz);}/*** 通过 name,clazz 获取指定的 bean 对象*/public static <T> T getBean(String name, Class<T> clazz) {return getApplicationContext().getBean(name, clazz);}
}
在WsMessageService中使用如下代码注入进去,但在类上必须要@Lazy进行懒加载,否则会报错
@Lazy
public class WsMessageService {
……private TestcaseService testcaseService = SpringContextUtil.getBean(TestcaseService.class);
……
}
不加@Lazy报错如下:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wsMessageService' defined in file [D:\javaworkspace\test-xxxx\tm-master\target\classes\cn\xxxxx\tmMaster\service\testcase\WsMessageService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.xxxxx.tmMaster.service.testcase.WsMessageService]: Constructor threw exception; nested exception is java.lang.NullPointerException
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wsMessageService' defined in file [D:\javaworkspace\test-xxxx\tm-master\target\classes\cn\xxxxx\tmMaster\service\testcase\WsMessageService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.xxxxx.tmMaster.service.testcase.WsMessageService]: Constructor threw exception; nested exception is java.lang.NullPointerExceptionat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1334) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:921) ~[spring-context-5.3.29.jar:5.3.29]at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.29.jar:5.3.29]at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) [spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) [spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) [spring-boot-2.7.14.jar:2.7.14]at cn.xxxxx.tmMaster.MasterApplication.main(MasterApplication.java:17) [classes/:na]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_382]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_382]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_382]at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_382]at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) [spring-boot-devtools-2.7.14.jar:2.7.14]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.xxxxx.tmMaster.service.testcase.WsMessageService]: Constructor threw exception; nested exception is java.lang.NullPointerExceptionat org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:224) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1326) ~[spring-beans-5.3.29.jar:5.3.29]... 22 common frames omitted
Caused by: java.lang.NullPointerException: nullat cn.xxxxx.tmMaster.utils.SpringContextUtil.getBean(SpringContextUtil.java:55) ~[classes/:na]at cn.xxxxx.tmMaster.service.testcase.WsMessageService.<init>(WsMessageService.java:48) ~[classes/:na]at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_382]at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_382]at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_382]at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_382]at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:211) ~[spring-beans-5.3.29.jar:5.3.29]... 24 common frames omitted
参考资料:
SpringBoot集成WebSocket实现客户端与服务端长连接通信_springboot实现websocket客户端_拄杖忙学轻声码的博客-CSDN博客 SpringBoot集成WebSocket实现客户端与服务端长连接通信
快速搭建springboot websocket客户端_springboot实现websocket客户端_wcybaonier的博客-CSDN博客 快速搭建springboot websocket客户端
相关文章:
Springboot2.7集成websocket及相关问题
1、集成websocket完整代码 导入maven依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency> 服务端代码 (1)注入bean Configur…...

MES管理系统和ERP系统在生产制造管理中的应用
MES生产管理系统通过过程管理、质量管理、设备管理、产品跟踪和溯源、性能分析和物料管理等方面来管理生产制造,旨在建立规范的生产管理信息平台,提高企业核心竞争力。ERP系统则通过制定生产计划、细分物料需求计划、车间订单下达和生产回报等步骤进行生…...
Netty Channel 详解
优质博文:IT-BLOG-CN 一、Netty 服务端启动过程 【1】创建服务端Channel; 【2】初始化服务端Channel; 【3】注册Selector; 【4】端口绑定:我们分析源码的入口从端口绑定开始,ServerBootstrap的bind(int in…...

技师学院物联网实训室建建设方案
一、概述 1.1专业背景 物联网(Internet of Things)被称为继计算机、互联网之后世界信息产业第三次浪潮,它并非一个全新的技术领域,而是现代信息技术发展到一定阶段后出现的一种聚合性应用与技术提升,是随着传感网、通…...

SpringBoot项目--电脑商城【增加/减少购物车商品数量】
1.持久层[Mapper] 1.1规划需要执行的SQL语句 1.更新该商品的数量.此SQL语句无需重复开发 update t_cart set num?,modified_user?,modified_time? where cid? 2.首先进行查询需要操作的购物车数据信息【查看该条数据是否存在】 SELECT * FROM t_cart WHERE cid?2.接口…...

CSS元素浮动
概述 浮动简介 在最初,浮动是用来实现文字环绕图片效果的,现在浮动是主流的页面布局方式之一。 元素浮动后的特点 脱离文档流。不管浮动前是什么元素,浮动后,默认宽与高都是被内容撑开的(尽可能小)&am…...

MATLAB中islocalmin函数用法
目录 语法 说明 示例 向量中的局部最小值 矩阵行中的最小值 相隔最小值 最小值平台区 突出最小值 islocalmin函数的功能是计算局部最小值。 语法 TF islocalmin(A) TF islocalmin(A,dim) TF islocalmin(___,Name,Value) [TF,P] islocalmin(___) 说明 当在 A 的…...

Python+Requests+Pytest+YAML+Allure实现接口自动化
本项目实现接口自动化的技术选型:PythonRequestsPytestYAMLAllure ,主要是针对之前开发的一个接口项目来进行学习,通过 PythonRequests 来发送和处理HTTP协议的请求接口,使用 Pytest 作为测试执行器,使用 YAML 来管理测…...

双视觉Transformer(Dual Vision Transformer)
摘要 已经提出了几种策略来减轻具有高分辨率输入的自注意机制的计算:比如将图像补丁上的全局自注意过程分解成区域和局部特征提取过程,每个过程都招致较小的计算复杂度。尽管效率良好,这些方法很少探索所有补丁之间的整体交互,因…...

MES系统成为工业4.0首选,制造业真正数字化车间你看过吗?
在日益激烈的市场竞争中,MES管理系统已经成为企业提升生产效率、降低成本、提高竞争力的关键。通过MES管理系统实现数据集成和分析,能够对产品制造过程的各个环节进行可视化控制,从设计、制造、质量、物流等环节全面掌控信息,实现…...
Vuex有几种属性以及它们的意义
有五种,分别是 State、 Getter、Mutation 、Action、 Module。 一、State Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实…...

PRBP20P-10/250C-EB、PRDP6G-10/30-CB电液比例直动式先导减压阀放大板
PRDP6P-10/30-CB、PRDP6R-10/50-DC、PRDP6G-10/30-CC、PRDP6P-10/50-CB、PRDP6R-10/30-CC、PRDP6G-10/30-CB电液比例直动式先导减压阀 PRBP10P-10/50C-EB、PRBP20P-10/100C-EC、PRBP30P-10/150C-EB、PRBP20P-10/250C-EB、PRBP10P-10/315C-EC、PRBP30P-10/350C-EB电液比例柱塞平…...

GDB之常见缩写命令(十九)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
MarkText快捷键(随时补充中)
MarkText快捷键 ctrl1:一号标题 (需要手动在【左上角】-【file】-【preferences】-【Key Bindings】-【 Transform into Heading 1】手动调整,先将【Switch tab to the 1st】占用快捷键删除才能在下面添加) ctrlg:添加…...
每日一题 1601最多可达成的换楼请求数目(子集模版)
题目 1601 我们有 n 栋楼,编号从 0 到 n - 1 。每栋楼有若干员工。由于现在是换楼的季节,部分员工想要换一栋楼居住。 给你一个数组 requests ,其中 requests[i] [fromi, toi] ,表示一个员工请求从编号为 fromi 的楼搬到编号为…...

排序算法-归并排序
属性 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序&#…...
vue3 整合 springboot 打完整jar包
前端 .env.developmen VITE_APP_BASE_URL/api.env.production VITE_APP_BASE_URL/axios 配置 axios.defaults.baseURL import.meta.env.VITE_APP_BASE_URLpackage.json "scripts": {"dev": "vite --mode development","build": &…...
依赖倒转原则是什么?
依赖倒转原则(Dependency Inversion Principle)是面向对象设计中的另一个基本原则,它是由Robert C. Martin提出的,它的中心思想是面向接口编程,该原则指出高层模块不应该依赖于低层模块,两者都应该依赖于抽…...
什么是GPT与MBR
GPT(GUID Partition Table)和MBR(Master Boot Record)是两种不同的磁盘分区表格式。 MBR是一种较早的磁盘分区表格式,它使用512字节的扇区作为存储空间。MBR分区表可以定义最多4个主分区,每个主分区都可以…...

前后端开发接口联调对接参数
前言 一个完整的互联网系统项目,需要前后端配合,进行上线,针对前端开发者,现在互联网主流的项目都是前后端分离 也就是后端负责提供数据接口,前端负责UI界面数据渲染 凡是在前台数据展示与用户交互的,都是由前端来实现的,而数据来源是由后台服务提供的 在浏览器c端能够发送后端…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...