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端能够发送后端…...
【紧急预警】CPython 3.12升级后,3款主流内存工具失效!2024最稳选型组合(含兼容性补丁与迁移路径)
第一章:Python 内存检测工具选型的底层逻辑与演进脉络Python 内存管理机制以引用计数为核心,辅以循环垃圾回收器(GC)和内存池(pymalloc),这决定了内存问题往往隐匿于对象生命周期、引用链异常或…...
M9A智能助手:为《重返未来:1999》玩家解放时间的自动化解决方案
M9A智能助手:为《重返未来:1999》玩家解放时间的自动化解决方案 【免费下载链接】M9A 1999 小助手 项目地址: https://gitcode.com/gh_mirrors/m9/M9A 在当今快节奏的游戏环境中,玩家常常需要在重复性日常任务上投入大量时间ÿ…...
实战教学应用:基于快马平台开发生物繁殖课互动学习与测评系统
作为一名生物老师,我一直在寻找能够让学生更直观理解繁殖知识的教学工具。最近尝试用InsCode(快马)平台开发了一个互动学习系统,效果出乎意料的好。这个平台最棒的地方是,不需要复杂的服务器配置,就能把想法快速变成可实际使用的教…...
RTX 4090显卡福利:Qwen2.5-VL-7B-Instruct轻量化部署,支持对话历史管理
RTX 4090显卡福利:Qwen2.5-VL-7B-Instruct轻量化部署,支持对话历史管理 1. 项目概述 Qwen2.5-VL-7B-Instruct是阿里通义千问推出的多模态大模型,专为视觉交互任务优化。本教程将展示如何在RTX 4090显卡上实现该模型的轻量化部署,…...
Qwen2-VL-2B-Instruct性能优化:Web服务并发请求处理与队列管理
Qwen2-VL-2B-Instruct性能优化:Web服务并发请求处理与队列管理 当你的AI图片分析服务突然火了,用户蜂拥而至,同时上传几十张图片要求分析,会发生什么?最直接的结果可能就是服务器卡死,用户看到“服务超时”…...
PasteMD真实案例分享:从零散笔记到结构化学习计划的全过程
PasteMD真实案例分享:从零散笔记到结构化学习计划的全过程 1. 引言:当杂乱笔记遇上智能格式化 你是否经历过这样的困境?电脑桌面上散落着十几个临时创建的记事本文件,手机备忘录里堆满了未经整理的零散想法,会议录音…...
SEO_避开这些常见误区,让你的SEO效果翻倍
<h2>避开这些常见误区,让你的SEO效果翻倍</h2> <p>在当今的互联网时代,搜索引擎优化(SEO)已经成为了每个网站和博客运营者必须掌握的技能之一。许多人在进行SEO时却会犯一些常见的错误,这些错误不仅…...
Swift-All镜像入门:手把手教你快速部署,无需配置轻松上手
Swift-All镜像入门:手把手教你快速部署,无需配置轻松上手 想体验600大模型和300多模态模型的强大能力,却被复杂的安装配置劝退?Swift-All镜像就是为你准备的"开箱即用"解决方案。本文将带你从零开始,一步步…...
LyricsX:突破平台限制,重构macOS歌词体验的开源解决方案
LyricsX:突破平台限制,重构macOS歌词体验的开源解决方案 【免费下载链接】LyricsX 🎶 Ultimate lyrics app for macOS. 项目地址: https://gitcode.com/gh_mirrors/ly/LyricsX 在流媒体音乐蓬勃发展的今天,音乐爱好者们却常…...
遥感影像配准总对不齐?OpenCV+RST+PROJ4三重坐标系对齐实战(附WGS84→UTM→影像本地坐标的转换矩阵速查表)
第一章:Shell脚本的基本语法和命令Shell脚本是Linux/Unix系统自动化任务的核心工具,以可执行文本文件形式存在,由Bash等shell解释器逐行解析运行。其语法简洁但严谨,对空格、分号、引号和换行符敏感,需严格遵循语法规则…...
