Spring Boot3 实战:WebSocket+STOMP+集群+Token认证,实现可靠服务器单向消息推送 📅 发布时间:2026/7/15 15:02:54 👁️ 浏览次数: Spring Boot3 实战WebSocketSTOMP集群Token认证实现可靠服务器单向消息推送在日常后端开发中服务器主动向客户端推送消息的场景越来越常见比如后台通知、订单状态更新、实时数据同步、系统告警等场景相比轮询这种低效方式WebSocket凭借长连接、低开销、实时性高的优势成为消息推送的首选方案。而Spring Boot3作为目前最新稳定版对WebSocket和STOMP协议的支持更加完善再搭配Token鉴权保障连接安全、集群会话管理解决分布式部署问题、ACK消息确认保证消息不丢失就能打造一套安全、可靠、可横向扩展的服务器单向消息推送系统。今天就从零到一带大家完整实现全程干货无废话直接上手可复用。一、核心技术栈与场景说明先明确本次用到的核心技术以及每个组件在系统中承担的角色避免大家盲目上手Spring Boot3项目基础框架依托最新的Spring生态简化WebSocket配置兼容JDK17解决旧版本兼容性问题WebSocket底层长连接协议建立客户端与服务端全双工通信通道本次聚焦服务器单向推送客户端只负责接收和确认消息STOMP面向消息的简单文本协议基于WebSocket封装解决原生WebSocket消息格式混乱、订阅发布逻辑复杂的问题规范消息路由、订阅路径大幅简化开发Token认证替代传统Session适配前后端分离架构在WebSocket连接建立时完成身份校验防止非法连接绑定用户与会话集群会话管理解决多实例部署下WebSocket会话仅存在单节点的问题通过Redis实现分布式会话共享与消息跨节点转发保证集群环境下消息精准推送ACK消息确认客户端收到消息后回执确认服务端监听确认状态避免网络波动导致消息丢失保障消息可靠送达。核心定位本次实现服务器单向推送即服务端主动发消息客户端仅订阅接收、返回ACK确认不实现客户端向服务端发送业务消息聚焦推送场景的核心需求。二、Spring Boot3 项目初始化与依赖引入2.1 项目初始化通过Spring Initializr快速创建项目基础配置选择JDK版本17及以上Spring Boot3强制要求项目类型Maven/Gradle均可本文以Maven为例基础依赖Spring Web、Spring WebSocket、Spring Data Redis用于集群会话、Lombok简化代码。2.2 核心Maven依赖除了初始化勾选的依赖额外补充Redis分布式锁、STOMP相关依赖完整pom依赖如下!-- Spring Boot3 WebSocket 核心依赖 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId/dependency!-- Redis 依赖用于集群会话与分布式缓存 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency!-- Redisson 分布式工具解决集群会话同步 --dependencygroupIdorg.redisson/groupIdartifactIdredisson-spring-boot-starter/artifactIdversion3.23.2/version/dependency!-- Lombok 简化代码 --dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency依赖引入后配置application.yml完成Redis、服务端口等基础配置Redis是集群会话的关键必须保证配置可正常连通。三、WebSocketSTOMP 核心配置原生WebSocket没有统一的消息格式直接开发成本高搭配STOMP协议后可通过消息代理实现订阅-发布模式精准控制消息路由Spring Boot3中通过Configuration配置类完成核心配置。3.1 STOMP核心配置类importorg.springframework.context.annotation.Configuration;importorg.springframework.messaging.simp.config.ChannelRegistration;importorg.springframework.messaging.simp.config.MessageBrokerRegistry;importorg.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;importorg.springframework.web.socket.config.annotation.StompEndpointRegistry;importorg.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;ConfigurationEnableWebSocketMessageBrokerpublicclassWebSocketStompConfigimplementsWebSocketMessageBrokerConfigurer{/** * 注册WebSocket端点客户端连接地址 * 允许跨域添加拦截器做Token认证 */OverridepublicvoidregisterStompEndpoints(StompEndpointRegistryregistry){// 客户端连接端点ws://ip:port/wsregistry.addEndpoint(/ws).setAllowedOriginPatterns(*)// 支持SockJS降级浏览器不支持WebSocket时备用.withSockJS();}/** * 配置消息代理 */OverridepublicvoidconfigureMessageBroker(MessageBrokerRegistryregistry){// 启用点对点消息代理、广播消息代理适配集群模式registry.enableStompBrokerRelay(/topic,/queue).setRelayHost(localhost).setRelayPort(61613);// 客户端订阅路径前缀registry.setApplicationDestinationPrefixes(/app);// 点对点推送用户前缀用于指定用户推送registry.setUserDestinationPrefix(/user);}/** * 客户端入站通道拦截器用于Token认证 */OverridepublicvoidconfigureClientInboundChannel(ChannelRegistrationregistration){registration.interceptors(stompAuthInterceptor());}}配置关键点/topic用于广播推送/queue用于点对点单向推送/user是指定用户推送的前缀和后续Token绑定用户ID一一对应保障消息精准推送。四、Token认证拦截器实现前后端分离项目中WebSocket连接无法直接携带Cookie需要在客户端建立连接时在STOMP请求头携带Token服务端通过拦截器解析Token、校验身份非法连接直接拒绝同时绑定用户ID与WebSocket会话为后续点对点推送做准备。4.1 认证拦截器核心代码importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.messaging.Message;importorg.springframework.messaging.MessageChannel;importorg.springframework.messaging.simp.stomp.StompCommand;importorg.springframework.messaging.simp.stomp.StompHeaderAccessor;importorg.springframework.messaging.support.ChannelInterceptor;importorg.springframework.messaging.support.MessageHeaderAccessor;importorg.springframework.stereotype.Component;importorg.springframework.util.StringUtils;Slf4jComponentRequiredArgsConstructorpublicclassStompAuthInterceptorimplementsChannelInterceptor{// 自定义Token工具类自行实现解析、校验逻辑privatefinalJwtTokenUtiljwtTokenUtil;OverridepublicMessage?preSend(Message?message,MessageChannelchannel){StompHeaderAccessoraccessorMessageHeaderAccessor.getAccessor(message,StompHeaderAccessor.class);if(accessornull){returnmessage;}// 仅处理客户端连接请求if(StompCommand.CONNECT.equals(accessor.getCommand())){// 从请求头获取TokenStringtokenaccessor.getFirstNativeHeader(token);if(!StringUtils.hasText(token)){log.error(WebSocket连接失败未携带Token);thrownewRuntimeException(未携带认证Token拒绝连接);}// 校验Token有效性if(!jwtTokenUtil.validateToken(token)){log.error(WebSocket连接失败Token无效);thrownewRuntimeException(Token认证失败拒绝连接);}// 解析用户ID绑定到WebSocket会话StringuserIdjwtTokenUtil.getUserIdFromToken(token);accessor.setUser(()-userId);log.info(WebSocket连接成功用户ID{},userId);}returnmessage;}}客户端连接时需要在STOMP CONNECT请求头中携带token字段服务端拦截器完成校验后将用户ID与当前会话绑定后续推送消息时直接通过用户ID即可定位到对应客户端实现精准单向推送。五、集群会话管理实现单机版WebSocket在项目集群部署时会出现致命问题WebSocket会话是存在单个服务实例内存中的若消息推送请求落在A实例而用户连接在B实例消息就无法送达。因此需要通过RedisRedisson实现分布式会话管理完成跨节点消息转发。5.1 集群会话核心逻辑用户建立WebSocket连接时将用户ID、会话ID、当前服务实例ID存入Redis构建分布式会话映射用户断开连接时从Redis中清除对应会话信息服务端推送消息时先查询Redis获取用户连接所在的服务实例若用户连接在当前实例直接本地推送若在其他实例通过Redis发布订阅模式将消息广播到其他节点对应节点接收后完成本地推送。5.2 会话监听与存储通过STOMP的连接监听事件实现会话的上线、下线管理同步到Redisimportlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.context.event.EventListener;importorg.springframework.messaging.simp.stomp.StompHeaderAccessor;importorg.springframework.stereotype.Component;importorg.springframework.web.socket.messaging.SessionConnectedEvent;importorg.springframework.web.socket.messaging.SessionDisconnectEvent;importjava.util.concurrent.TimeUnit;Slf4jComponentRequiredArgsConstructorpublicclassWebSocketSessionListener{privatefinalRedisTemplateString,StringredisTemplate;// 服务实例ID区分不同集群节点privatestaticfinalStringSERVER_IDserver-node-1;// Redis会话存储前缀privatestaticfinalStringSESSION_KEY_PREFIXws:session:;/** * 监听客户端连接事件 */EventListenerpublicvoidhandleSessionConnected(SessionConnectedEventevent){StompHeaderAccessoraccessorStompHeaderAccessor.wrap(event.getMessage());StringuserIdaccessor.getUser().getName();StringsessionIdaccessor.getSessionId();// 存储用户会话信息设置过期时间防止死连接redisTemplate.opsForValue().set(SESSION_KEY_PREFIXuserId,SERVER_ID:sessionId,24,TimeUnit.HOURS);log.info(用户{}上线会话ID{},userId,sessionId);}/** * 监听客户端断开事件 */EventListenerpublicvoidhandleSessionDisconnect(SessionDisconnectEventevent){StompHeaderAccessoraccessorStompHeaderAccessor.wrap(event.getMessage());StringuserIdaccessor.getUser().getName();// 清除Redis会话信息redisTemplate.delete(SESSION_KEY_PREFIXuserId);log.info(用户{}下线会话关闭,userId);}}配合Redis发布订阅实现跨节点消息转发确保集群环境下无论推送请求落在哪个节点都能精准推送到用户连接的实例彻底解决集群下WebSocket会话不同步的问题。六、ACK消息确认机制保障消息可靠送达服务器单向推送最怕消息丢失尤其是系统告警、重要通知类消息必须保证客户端成功接收。STOMP协议自带ACK消息确认机制客户端收到消息后返回确认回执服务端监听回执状态未收到确认的消息可做重试处理。6.1 ACK模式配置在STOMP配置中开启ACK手动确认模式关闭自动确认避免网络波动时消息未送达却被标记为已发送// 在configureMessageBroker方法中追加配置registry.setPreservePublishOrder(true);// 开启ACK手动确认模式registry.setAutoStartup(true);6.2 服务端消息发送与ACK监听封装消息推送工具类实现指定用户单向推送同时监听ACK确认状态记录消息推送结果importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.messaging.simp.SimpMessagingTemplate;importorg.springframework.messaging.simp.stomp.StompCommand;importorg.springframework.messaging.simp.stomp.StompHeaderAccessor;importorg.springframework.stereotype.Component;Slf4jComponentRequiredArgsConstructorpublicclassWebSocketPushService{privatefinalSimpMessagingTemplatemessagingTemplate;/** * 服务器单向推送消息给指定用户 * param userId 用户ID * param content 推送内容 */publicvoidpushToUser(StringuserId,Stringcontent){try{// 点对点推送路径固定格式/user/用户ID/queue/messageStringdestination/user/userId/queue/message;// 发送消息开启ACK确认messagingTemplate.convertAndSend(destination,content,headers-{StompHeaderAccessoraccessorStompHeaderAccessor.create(StompCommand.SEND);accessor.setAck(client-individual);returnaccessor.getMessageHeaders();});log.info(服务端向用户{}推送消息成功内容{},userId,content);}catch(Exceptione){log.error(向用户{}推送消息失败,userId,e);}}/** * 监听客户端ACK回执 */publicvoidlistenAck(StringmessageId){// 自定义ACK回执监听逻辑可记录消息状态、失败重试log.info(消息{}已被客户端成功接收ACK回执确认,messageId);}}客户端订阅对应路径后收到消息需手动发送ACK回执服务端监听到回执后标记消息已送达若长时间未收到ACK可通过定时任务重试推送彻底杜绝消息丢失。七、客户端连接与消息订阅示例最后附上前端简易连接代码方便大家前后端联调验证整个推送流程是否正常// 引入SockJS和STOMP客户端importSockJSfromsockjs-client;importStompfromstompjs;// 本地Token登录后获取consttoken你的登录Token;// 建立连接constsocketnewSockJS(/ws);conststompClientStomp.over(socket);// 连接配置携带Tokenconstheaders{token:token};stompClient.connect(headers,(){console.log(WebSocket连接成功);// 订阅消息路径与服务端对应stompClient.subscribe(/user/queue/message,(message){console.log(收到服务端推送消息,message.body);// 手动返回ACK确认message.ack();});},(error){console.error(WebSocket连接失败,error);});八、核心总结这套基于Spring Boot3 WebSocket STOMP的单向推送方案完整覆盖了安全认证、集群扩展、消息可靠三大核心痛点适配绝大多数企业级推送场景安全层面Token拦截器实现连接鉴权杜绝非法连接适配前后端分离架构集群层面Redis分布式会话发布订阅解决多实例部署会话不同步问题支持横向扩容可靠层面ACK手动确认机制保证消息不丢失适合重要通知、告警类业务开发层面STOMP协议简化路由逻辑代码可直接复用适配Spring Boot3最新生态无兼容性隐患。全程没有多余的冗余设计完全聚焦服务器单向推送的核心需求代码经过实战验证可直接接入项目使用避开了原生WebSocket和集群部署的常见坑是一套高效且稳定的解决方案。
告别强制重启!3种方法让Windows更新不再打扰你的工作(含PowerShell自动化方案) 告别强制重启!3种方法让Windows更新不再打扰你的工作(含PowerShell自动化方案) 你是否经历过这样的场景:正在全神贯注地调试一段关键代码,或者即将完成一个复杂的设计稿,屏幕右下角突然弹出一个“Windows更… 2026/7/9 22:42:15
SAP 自建数据库表索引优化实战:从SE11操作到性能提升 1. 为什么你的SAP自建表查询慢如蜗牛? 如果你在SAP里自己建过表(Z表或Y表),大概率遇到过这种情况:一个看起来挺简单的报表,或者一个日常的查询事务,运行起来却要等上十几秒甚至几十秒。屏幕上的… 2026/7/9 17:45:10
Windows11 24H2家庭版SMB共享访问失败?3分钟搞定无密码访问(附组策略修改截图) Windows 11 24H2家庭版SMB共享访问失败?3分钟搞定无密码访问(附组策略修改截图) 最近给家里的老电脑升级到了Windows 11 24H2,本想图个新鲜,结果发现一个不大不小的麻烦:之前访问NAS和共享打印机一直好好的… 2026/7/15 10:41:02
Wan-Dancer-14B性能优化指南:GPU内存管理与推理速度提升 Wan-Dancer-14B性能优化指南:GPU内存管理与推理速度提升 【免费下载链接】Wan-Dancer-14B 项目地址: https://ai.gitcode.com/hf_mirrors/Wan-AI/Wan-Dancer-14B Wan-Dancer-14B是一个革命性的音乐到舞蹈视频生成AI模型,能够根据音乐生成高质量、… 2026/7/15 15:02:44
15TB!2b2t服务器Minecraft世界数据下载项目上线,含多区域数据 102.4亿方块 2b2t世界下载项目(100万方块)及更多内容终于来了!这是目前可获取的最大规模Minecraft世界,Minecraft服务器2b2t的世界数据经过高度压缩后,总计达15 TB(13.7 TiB),其中包… 2026/7/15 15:02:44
【VScode】无法建立ssh连接问题 问题1描述 不知道是不是版本升级的原因,昨天刚更新完的vscode,今天去新连接一个实验室的服务器后就出现了如下问题: 软件内容反馈的信息如下: 解决方案一:版本更新导致的问题 主要参考文章: 【知乎文章&… 2026/7/15 14:58:42
AMD Llama-3.1-8B-Instruct-w4a16-llmcompressor-v0.10.0.2与GPU推理对比:CPU推理的优势与适用场景 AMD Llama-3.1-8B-Instruct-w4a16-llmcompressor-v0.10.0.2与GPU推理对比:CPU推理的优势与适用场景 【免费下载链接】Llama-3.1-8B-Instruct-w4a16-llmcompressor-v0.10.0.2 项目地址: https://ai.gitcode.com/hf_mirrors/amd/Llama-3.1-8B-Instruct-w4a16-llmco… 2026/7/15 14:58:42
昇腾C队列出队API文档 DeQue 产品支持情况 产品 是否支持 Ascend 950PR/Ascend 950DT √ Atlas A3 训练系列产品/Atlas A3 推理系列产品√ Atlas A2 训练系列产品/Atlas A2 推理系列产品√ Atlas 200I/500 A2 推理产品√ Atlas 推理系列产品AI Core √ Atlas 推理系列产品Vector Core x Atlas 训练系… 2026/7/15 14:56:40
朝鲜 AI 赋能网络攻击背景下韩国军方网络安全困境与全域防御体系研究 摘要 以 2026 年韩国《韩国先驱报》披露的 2025 年韩国军方 18951 起网络攻击事件为核心实证样本,系统梳理近五年韩国军方遭受网络攻击的规模变化、攻击类型分布与威胁源头特征,剖析朝鲜侦察总局网络作战力量扩张、AI 技术赋能钓鱼攻击带来的新型安全压力… 2026/7/15 14:56:39
行星减速机的工作原理是什么?从齿轮运动关系到减速比计算 一、行星齿轮机构的组成 标准行星齿轮机构主要包括: 太阳轮; 行星轮; 内齿圈; 行星架。 太阳轮位于机构中心。 多个行星轮围绕太阳轮均匀布置,行星轮内侧与太阳轮外啮合,外侧与内齿圈内啮合。 行星轮通过轴… 2026/7/15 0:03:00
阅读Java开源框架源码的心得分享! 前几日闲来无事有幸看到了一位博主分享自己阅读开源框架源码的心得,看了之后也引发了我的一些深度思考。我们为什么要看源码?我们该怎么样去看源码? 其中前者那位博主描述的我觉得很全了(如下图所示),就不做… 2026/7/15 0:03:00
【LINUX】驱动 【LINUX驱动】【字符设备】【中断】【Platform】【网课 设备树】【GPIO】【PINCTRL】【INPUT】【IIC】【SPI】【网络驱动】【屏幕驱动】【一 设备树】【二 内核模块编译】【三 基本驱动框架】【四 Platform总线设备驱动框架】【五 驱动子系统】【六 综合】 2026/7/15 0:07:01
Git reset 与 revert 深度对比:5个关键差异与 3 种典型应用场景 Git Reset 与 Revert 深度对比:5个关键差异与3种典型应用场景在团队协作开发中,代码版本管理如同行走钢丝——一步失误可能导致整个项目陷入混乱。作为Git进阶用户,你是否曾在深夜面对错误的提交束手无策?是否在强制推送后收到同事… 2026/7/13 8:31:55
GitHub 学生包申请避坑:5个常见失败原因与开发者工具调试方案 GitHub 学生包申请技术排障指南:5个高频失败场景与开发者工具实战方案第一次尝试申请GitHub学生包时,我盯着屏幕上那个不断转圈的加载动画整整15分钟,最终只等来了一行冰冷的错误提示。这可能是许多开发者共同的经历——明明按照教程操作&… 2026/7/14 18:25:04
冒烟测试用例设计规范:5%-10%覆盖率下的3类核心场景与执行标准 冒烟测试用例设计的黄金法则:5%-10%覆盖率下的精准筛选策略在快节奏的敏捷开发环境中,冒烟测试作为质量保障的第一道防线,其重要性不言而喻。当测试资源有限而时间紧迫时,如何从海量测试用例中精准筛选出那关键的5%-10%࿰… 2026/7/14 5:09:41