【WebSocket】在SSM项目中配置websocket
在SSM项目中配置websocket
最近在ssm项目中配置了websocket,踩了很多坑,来分享一下
本文暂不提供发送消息等内容的代码逻辑(后续也许会补充),如果你直接复制这类可能会对配置造成更大的麻烦(博主就是复制了他人逻辑导致连接后秒断开连接,排查了很长时间),建议看完本文配置成功后,去其他文章或者github寻找相应代码逻辑
1.Maven依赖
首先是jackson的依赖
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.3.1</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.3.3</version></dependency>
然后是spring关于websocket的依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId><version>${spring.version}</version></dependency>
这里的${spring.version}需要注意,一定要和自己的spring版本匹配,所以推荐用这种形式,而不是直接用x.x.x.RELEASE
另外在spring4.0.5.RELEASE之前与其以后,session获取参数的方法有些不同,需要注意
本文使用的是
<spring.version>4.2.5.RELEASE</spring.version>
注意:请删除所有关于javax的依赖,将本地的tomcat引入库中,否则可能会出现类型转换异常导致连接报错(你可以继续下面的步骤,如果在启动测试时出现该问题,再回来尝试解决)


2.配置类
首先在我们的项目中创建如下结构

当然也可以不使用这样的结构,如果你的项目中本来有config、Interceptor、handler包,可以将这些类放入其中
注意以下代码没有给出包名,如需复制请注意
首先是WebSocketConfig.java
import org.springframework.stereotype.Component;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;import javax.annotation.Resource;/*** WebScoket配置处理器*/
@Component
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@ResourceMyWebSocketHandler handler;@ResourceHandShake handShake;public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {//浏览器支持websocketregistry.addHandler(handler, "/ws").addInterceptors(handShake);//浏览器不支持的话,需要socketjs引入支持registry.addHandler(handler, "/ws/sockjs").addInterceptors(handShake).withSockJS();}}
这个类的作用是配置websocket的链接地址,分为浏览器支持websocket和不支持websocket的情况,不支持可以引入sockjs(某些环境下使用这行代码会导致无法连接,不放心可以删去)
websocket连接地址是
ws://ip:端口号/项目名称/ws
ws与上述配置类相对应
这个连接地址是可以以?的形式传参数的,例如
"ws://ip:端口号/项目名称/ws?userId="+userId
第二个类是HandShake.java
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;import javax.servlet.http.HttpSession;
import java.util.Map;/*** Socket建立连接(握手)和断开*/
@Component
public class HandShake implements HandshakeInterceptor {@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {// 1.获取sessionServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;HttpSession session = servletRequest.getServletRequest().getSession(false);// 2.从session中获取uidLong uid = (Long) session.getAttribute("uid");// 3.做正向判断,如果uid是空值直接返回false,拒绝握手if (uid == null){return false;}// 4.输出日志System.out.println("Websocket:用户[ID:" + uid + "]准备进行握手");// 5.将用户id存入mapattributes.put("uid", uid);// 6.可以进行握手return true;}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {System.out.println("after hand");}}
这个类是websocket的握手拦截器,会拦截websocket链接地址的请求,进行握手,不建议在该类中做业务处理
最后是MyWebSocketHandler.java
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import java.io.IOException;/*** Socket处理器*/
@Component
public class MyWebSocketHandler implements WebSocketHandler {@Overridepublic void afterConnectionEstablished(WebSocketSession session)throws Exception {System.out.println("ConnectionEstablished");}@Overridepublic void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {}/*** 消息传输错误处理*/@Overridepublic void handleTransportError(WebSocketSession session,Throwable exception) throws Exception {System.out.println("TransportError");}/*** 关闭连接后*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {System.out.println("ConnectionClosed");}@Overridepublic boolean supportsPartialMessages() {return false;}
}
这个类是对websocket的各种状态作出相应的处理,如开头所说,本文不会给出相应的逻辑,防止出现错误,这里真的很坑
大体思路就是通过方法中的WebSocketSession获取到session中的用户id,再注入自己的userService(或者其他service层)去完成业务,同时可以在本类中使用ConcurrentHashMap或者直接开一个线程来实现同时在线人数等功能
发送信息的逻辑推荐对信息进行封装,构建实体类
此外你还可以创建一个相应的Controller,通过注入MyWebSocketHandler来建立相应功能的请求地址
import com.webchat.websocket.MyWebSocketHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/websocket")
public class WebSocketController {@AutowiredMyWebSocketHandler handler;}
3.JS部分
最后是js部分
let websocket = new WebSocket("ws://ip:端口号/项目名称/ws?userId="+userId);websocket.onmessage = function(event) {console.log(event.data)};websocket.onopen = function (event){console.log("连接成功")}websocket.onerror = function (event){console.log("连接错误")}websocket.onclose = function (event){console.log('websocket 断开: ' + event.code + ' ' + event.reason + ' ' + event.wasClean)}
注意更改地址
4.测试结果
测试结果如下


至此,ssm项目中配置websocket就完成了
如果在测试中出现其他错误,可以根据输出的event.code来匹配错误原因,如果连接后直接断开并显示1011请检查后端代码规范性
| 编码 | 原因 |
|---|---|
| 1000 | 正常关闭 当你的会话成功完成时发送这个代码 |
| 1001 | 离开 因应用程序离开且不期望后续的连接尝试而关闭连接时,发送这一代码。服务器可能关闭,或者客户端应用程序可能关闭 |
| 1002 | 协议错误 当因协议错误而关闭连接时发送这一代码 |
| 1003 | 不可接受的数据类型 当应用程序接收到一条无法处理的意外类型消息时发送这一代码 |
| 1004 | 保留 不要发送这一代码。根据 RFC 6455,这个状态码保留,可能在未来定义 |
| 1005 | 保留 不要发送这一代码。WebSocket API 用这个代码表示没有接收到任何代码 |
| 1006 | 保留 不要发送这一代码。WebSocket API 用这个代码表示连接异常关闭 |
| 1007 | 无效数据 在接收一个格式与消息类型不匹配的消息之后发送这一代码。如果文本消息包含错误格式的 UTF-8 数据,连接应该用这个代码关闭 |
| 1008 | 消息违反政策 当应用程序由于其他代码所不包含的原因终止连接,或者不希望泄露消息无法处理的原因时,发送这一代码 |
| 1009 | 消息过大 当接收的消息太大,应用程序无法处理时发送这一代码(记住,帧的载荷长度最多为64 字节。即使你有一个大服务器,有些消息也仍然太大。) |
| 1010 | 需要扩展 当应用程序需要一个或者多个服务器无法协商的特殊扩展时,从客户端(浏览器)发送这一代码 |
| 1011 | 意外情况 当应用程序由于不可预见的原因,无法继续处理连接时,发送这一代码 |
| 1015 | TLS失败(保留) 不要发送这个代码。WebSocket API 用这个代码表示 TLS 在 WebSocket 握手之前失败。 |
| 0 ~ 999 | 禁止 1000 以下的代码是无效的,不能用于任何目的 |
| 1000 ~ 2999 | 保留 这些代码保留以用于扩展和 WebSocket 协议的修订版本。按照标准规定使用这些代码,参见表 3-4 |
| 3000 ~ 3999 | 需要注册 这些代码用于“程序库、框架和应用程序”。这些代码应该在 IANA(互联网编号分配机构)公开注册 |
| 4000 ~ 4999 | 私有 在应用程序中将这些代码用于自定义用途。因为它们没有注册,所以不要期望它们能被其他 WebSocket广泛理解 |
相关文章:
【WebSocket】在SSM项目中配置websocket
在SSM项目中配置websocket 最近在ssm项目中配置了websocket,踩了很多坑,来分享一下 本文暂不提供发送消息等内容的代码逻辑(后续也许会补充),如果你直接复制这类可能会对配置造成更大的麻烦(博主就是复制…...
node-red中创建自定义节点 JavaScript 文件API编写详解
前言 在node-red中如果你没有找到自己需要的节点时,那么你可以自定义一个节点来满足自己的需求。之前的文章中,我有简单介绍过如何创建一个节点,并以转换大小写来举例。例子虽然简单,但可以让大家了解创建自定义节点的步骤以及一个节点的组成部分。那么本篇将会聚焦在自定…...
华为OD机试 - 寻找路径 or 数组二叉树(C 语言解题)【独家】
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 使用说明本期题目:寻找路径…...
YOLOv7、YOLOv5改进之打印热力图可视化:适用于自定义模型,丰富实验数据
💡该教程为改进YOLO高阶指南,属于《芒果书》📚系列,包含大量的原创改进方式🚀 💡更多改进内容📚可以点击查看:YOLOv5改进、YOLOv7改进、YOLOv8改进、YOLOX改进原创目录 | 唐宇迪老师联袂推荐🏆 💡🚀🚀🚀内含改进源代码 按步骤操作运行改进后的代码即可�…...
【Java代码与架构之完美优化】篇1:代码质量优化通用准则
工欲善其事,必先利其器 1. 避免使用空块 常见空块一般有以下几种情况: 多余的分号:if(xxx);多余的大括号:if(xxx){这里没有内容}空finall语句:try{...}catch(...){...}finally{这里没有内容} 空块的存在࿰…...
Linux进程间通信详解(最全)
进程间的五种通信方式介绍 进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享内存、Socket(套接字&a…...
ROS 摄像头的使用
参考: youtubeArticulated Robotics 作者Josh Newans博客 建议: 这个只是我的看法,强烈建议看原视频或博客 png:无损压缩 jpeg:有损压缩 Driver Node 负责连接硬件设备,读取摄像头数据"ima…...
VR全景云展厅,实现7*24小时的线上宣传能力!
数字化时代,虚拟现实技术的应用越来越广泛,其中VR全景云展厅是一种新兴的展示方式,具有独特的展示优势。随着VR技术的不断发展,越来越多的企业、机构和个人开始使用VR全景云展厅来展示他们的产品和服务。一、展厅营销痛点1、实地到…...
RK3568平台开发系列讲解(显示篇) DRM显示系统组成分析
🚀返回专栏总目录 文章目录 一、DRM Framebuffer二、CRTC三、Planes四、Encoder五、Connector沉淀、分享、成长,让自己和他人都能有所收获!😄 📢让我们分析一下绿框中的五个部件,以及他们的联动。 一、DRM Framebuffer 与 framebuffer一样,是一片存放图像的内存区域,…...
WPF DataGrid控件的使用 使用列模板来进行数据格式的美化
<Grid><Grid.RowDefinitions><RowDefinition Height"0.1*" /><RowDefinition /></Grid.RowDefinitions><Button Content"刷新"FontSize"25"Command"{Binding ExecuteRefreshCommand}" /><Dat…...
elasticsearch自定义企业词典
我们中文分词用的是ik,但是ik只是对基本的中文词进行了分词,而对于企业或者人名没有进行分词。比如,我搜索中国平安,那么ik只能分成中国、平安如果这样,这肯定是不行滴!接下来,俺就教你…...
【AcWing】学了一坤时才明白的一道题
🎆音乐分享 (点击链接可以听哦) The Right Path - Thomas Greenberg 这道题小吉花了一坤时才弄明白,虽然花的时间有点长 但是至少是明白了 😎😎😎😎😎😎 …...
ES6的export和import
ES6中的模块加载ES6 模块是编译时加载,编译时就能确定模块的依赖关系,以及输入和输出的变量,相比于CommonJS 和 AMD 模块都只能在运行时确定输入输出变量的加载效率要高。严格模式ES6 的模块自动采用严格模式,不管你有没有在模块头…...
ASEMI高压MOS管20N60参数,20N60尺寸,20N60体积
编辑-Z ASEMI高压MOS管20N60参数: 型号:20N60 漏极-源极电压(VDS):600V 栅源电压(VGS):30V 漏极电流(ID):20A 功耗(PDÿ…...
【备战面试】TCP的三次握手与四次挥手
本篇总结的是计算机网络知识相关的面试题,后续也会更新其他相关内容 文章目录1、TCP头部结构2、三次握手3、四次挥手4、为什么TCP连接的时候是三次?两次是否可以?5、为什么TCP连接的时候是三次,关闭的时候却是四次?6、…...
【模板进阶】
目录 1. 非类型模板参数 2. 模板的特化 2.1 概念 2.2 函数模板特化 2.3 类模板特化 2.3.1 全特化 3 模板分离编译 3.1 什么是分离编译 3.2 模板的分离编译 4. 模板总结 有需要的老哥可以先看看模板的介绍:http://t.csdn.cn/2TkUYhttp://t.csdn.cn/2TkUY 1. …...
Tech Talk | 电致变色技术带来的智能AR体验
2023年2月27日,小米在2023MWC世界移动通信大会上,正式发布了小米无线AR眼镜探索版。这款产品搭载了创新的数控电致变色镜片,能适应不同光环境,遮光模式可以在观影时更沉浸,通透模式又能让AR虚实结合的体验更生动。“ 本…...
ACWING蓝桥杯每日一题python(持续更新
ACWing蓝桥杯每日一题 一直没时间去总结算法,终于有空可以总结一下刷的acwing了,因为没时间所以最近只刷了ACWING的蓝桥杯每日一题。。。真是该死 1.截断数组 首先我们要知道,如果sum(a)不能被3整除或者len(a) < 3 ,那么他肯…...
【Linux】进程状态(阻塞、挂起、僵尸进程)
文章目录1 阻塞与挂起1.1 阻塞1.2 挂起2 进程状态前言: 当我们在Windows下双击运行一个程序,或是在Linux下通过 ./ 加载运行一个程序,是否就代表对应的进程就一直处在运行状态呢?其实不然,一个进程有许多不同的状态。当…...
规约第二章
文章目录有限域的定义Definition of Finite Field单位元运算举例素数域群阿贝尔群阿贝尔循环群循环子群阿贝尔循环群且阶是素数的有限域的定义Definition of Finite Field 单位元 这里一般只需要记住2个0,1 。0是加法的单位元,1是乘法的单位元。以及逆…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...
