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

SpringBoot集成STOMP

参考:

【stomp 实战】Spring websocket使用详解和基本原理_spring stomp websocket-CSDN博客

WebSocket与STOMP通信技术详解_stomp websocket-CSDN博客

上一篇我们详细介绍了WebSocket作为一种全双工通信协议的基本概念、工作原理和实现方式。然而,在企业级应用或复杂系统中,仅仅使用原生WebSocket可能还不足以满足更高级的消息传递需求。这就是STOMP(Simple Text Oriented Messaging Protocol)协议发挥作用的地方。本文将深入探讨STOMP协议的本质、它与WebSocket的结合优势以及实际应用示例


STOMP是什么?

STOMP(Simple Text Oriented Messaging Protocol,简单文本导向消息协议)是一种应用层协议,设计用于在客户端和消息代理(如消息队列、消息中间件)之间进行异步消息传递。它最初是为Apache ActiveMQ设计的,现在已成为多种消息中间件支持的标准协议。

STOMP协议的核心特点:

  1. 简单易用:基于文本的协议,命令结构类似HTTP
  2. 跨语言支持:几乎所有主流编程语言都有STOMP客户端库
  3. 基于帧:所有通信基于帧(frame)进行,包含命令、头信息和消息体
  4. 发布/订阅模式:支持标准的发布/订阅消息模式
  5. 目的地导向:消息通过目的地(destination)进行路由

为什么要将STOMP与WebSocket结合使用

WebSocket提供了浏览器和服务器之间的双向通信通道,但它并没有定义应用层的消息格式和路由机制。这就像有了高速公路,但没有交通规则一样。将STOMP与WebSocket结合使用,可以获得以下几个方面的好处:

标准化的消息格式

原生WebSocket没有定义消息的格式,开发人员需要自行设计消息结构,这可能导致不一致和兼容性问题。STOMP提供了标准化的消息格式,包括命令、头信息和消息体,使消息交换更加规范和统一。

消息路由机制

STOMP的目的地(destination)概念允许消息按照特定的主题或队列进行路由,这使得复杂的消息分发变得简单。客户端可以订阅特定的目的地,只接收感兴趣的消息。

消息确认和事务支持

STOMP支持消息确认机制,确保消息被正确处理。同时,它还支持事务,可以将多个操作组合成一个原子单元

与消息中间件的无缝集成

STOMP可以与ActiveMQ、RabbitMQ、Apache Kafka等主流消息中间件无缝集成,使WebSocket应用能够利用这些成熟中间件的强大功能。

错误处理机制

STOMP提供了标准的错误处理机制,当出现问题时,服务器可以发送错误帧给客户端,包含详细的错误信息。


后端相关配置代码

依赖引入

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

这个包实际上引入了两个依赖spring-messaging 和 spring-websocket

stomp相关配置代码

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {// 注册STOMP端点,客户端将使用这个端点连接到STOMP服务器registry.addEndpoint("/upload-websocket").withSockJS()           // 启用SockJS降级支持.setHeartbeatTime(10000); // 心跳间隔}@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {// 启用一个简单的基于内存的消息代理,将消息返回给前缀为"/topic"的目的地config.enableSimpleBroker("/topic");// 指定应用程序目的地前缀// 客户端发送消息的目的地应该以"/app"开头config.setApplicationDestinationPrefixes("/app");}}

后端创建端点

registry.addEndpoint(“/upload-websocket”); 添加一个端点,前端可以通过这个端点,进行websocket通信,对应的前端代码可以这么写


前端订阅

config.enableSimpleBroker(“/topic”, “/queue”); 这个是启用消息broker。广播消息的前缀。当我们需要发送广播消息给客户端时,需要满足这个前缀条件。
前端这么订阅消息,是topic前缀

// 订阅公共聊天室话题
stompClient.subscribe('/topic/public', onMessageReceived);

后端代码通过消息broker,可以将此消息发送给订阅了"/topic/boardCast/hello"的客户端。

private final SimpMessageSendingOperations messagingTemplate;messagingTemplate.convertAndSend("/topic/public", chatMessage);

前端发送消息给后端

config.setApplicationDestinationPrefixes(“/app”); 这个是前端可以往这个路径发送消息。
前端代码这么写的:

后端可以定义一个controller,来接收这个消息,所以这个/app的意思可以理解为所有@MessageMapping的前缀。

@Controller
@Slf4j
public class ChatController {/*** 接收前端发送* stompClient.send("/app/chat.sendMessage", {}, JSON.stringify(chatMessage));** @param chatMessage* @return*/@MessageMapping("/chat.sendMessage")@SendTo("/topic/public")public ChatMessage sendMessage(@Payload ChatMessage chatMessage) {return chatMessage;}}

后端发送消息给前端

messagingTemplate.convertAndSend 方式

private final SimpMessageSendingOperations messagingTemplate;messagingTemplate.convertAndSend("/topic/public", chatMessage);

@MessageMapping + @SendTo 方式


代码示例

前端往/app/chat.sendMessage发送了一条消息

function sendMessage() {const messageContent = document.querySelector('#message-input').value.trim();if(messageContent && stompClient) {const chatMessage = {sender: sid,content: messageContent,type: 'CHAT'};// 发送消息到服务器stompClient.send("/app/chat.sendMessage", {}, JSON.stringify(chatMessage));document.querySelector('#message-input').value = '';}
}

后端需要注册/app前缀

然后定义一个Controller来接收用户消息, @MessageMapping(“/chat.sendMessage),这里就是子路径了,拼起来正好是/app/chat.sendMessage,这时Wesocket请求会到达sendMessage方法。 

@Controller
public class ChatController {@MessageMapping("/chat.sendMessage")@SendTo("/topic/public")public ChatMessage sendMessage(@Payload ChatMessage chatMessage) {return chatMessage;}
}

上面示例代码的执行流程,消息的流转如下图所示

  • 消息通过inboundChannel到服务器
  • 此时根据消息的前缀,会匹配出/app开头的,是需要找SimpAnnotationMethodMessageHandler。这个处理器,是找Controller来执行
  • Controller中收到该消息,其方法中调用了一个发送方法。发往/topic/boardCast/hello
  • 此时也会根据消息的前缀,找到消息处理器,SimpleBrokerMessageHandler
  • SimpleBrokerMessageHandler遍历用户会话,找到订阅了/topic/boardCast/hello的用户。通过outboundChannel将消息发送出去

以上就是用户发送一个消息,服务端接收。服务端同时再发送一条广播消息给对应的客户端的过程。

http://www.lryc.cn/news/611074.html

相关文章:

  • CS231n Lecture11 目标检测和图像分割笔记
  • mq_timedsend系统调用及示例
  • 浮动路由和BFD配置
  • 智能体架构与风险全景:从LLM工作流到OWASP Top 10安全浅谈
  • 本地使用uv管理的python项目怎么部署到服务器?
  • Web存储技术详解:sessionStorage、localStorage与Cookie
  • 每日五个pyecharts可视化图表-bars(4)
  • 手绘风格制图新选择:如何用Excalidraw+cpolar构建你的视觉化工作流?
  • 一次完整的 Docker 启动失败排错之旅:从 `start-limit` 到 `network not found
  • Docker Desktop
  • 利用DeepSeek编写带缓冲输出的V语言程序
  • P1103《书本整理》精讲
  • PowerBI VS QuickBI 实现图表的动态配色
  • linux-系统日志查看指令systemctl
  • 37.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--扩展功能--增加Github Action
  • STM32U575低功耗调试
  • Rust进阶-part3-生命周期
  • DAY 36 复习日
  • C++进阶—特殊类设计
  • 国产三防平板电脑是什么?三防平板推荐
  • Prometheus 监控平台部署 (云原生环境)
  • C语言基础_补充知识、数据类型转换、选择结构
  • OpenLayers学习(一)-基础
  • bcryptprimitives.dll是什么文件
  • 机器学习 集成学习之随机森林
  • 真正的多模态上下文学习需要关注视觉上下文
  • ASP3605I同步降压调节器的高频化设计与多相扩展技术优化方案
  • 利用链上数据进行数字资产量化因子发现
  • 关于怎么知道linux(ubuntu)系统交叉编译器的命令的方法:
  • 算法训练之哈希表