WebSocket的那些事(3-STOMP实操篇)
目录
- 一、序言
- 二、STOMP详解
- 1、STOMP简单介绍
- 2、STOMP协议内容
- 3、使用STOMP的好处
- 三、代码示例
- 1、Maven依赖
- 2、开启WebSocket消息代理
- 3、控制器
- 4、前端页面greeting.html
- 四、测试
- 1、连接服务端
- 2、发送消息
- 五、STOMP消息传播流程
- 六、结语
一、序言
上节中我们在 WebSocket的那些事(2-实操篇)中简单介绍了Spring中对于WebSocket的封装,并实现一个简单的服务端,这节我们将会结合STOMP子协议实现WebSocket通信。
二、STOMP详解
1、STOMP简单介绍
WebSocket协议定义了两种消息类型(文本类型和二进制类型),但是消息内容却是未定义的,下面我们介绍一下STOMP协议。
STOMP (Simple Text Oriented Messaging Protocol) 起源于脚本语言,比如Ruby、Python和Perl,用于连接企业消息代理,它可以用于任何可靠的双向网络协议中,如TCP和WebSocket。尽管STOMP是一个面向文本的协议,但消息负载可以是文本或者二进制。
STOMP基于WebSocket在客户端和服务端之间定义了一种机制,协商通过子协议(更高级的消息协议)来定义可以发送何种消息,每条消息的内容是什么,等等。
2、STOMP协议内容
STOMP是一个基于帧的协议,帧的结构如下:
COMMAND
header1:value1
header2:value2Body
客户端可以用SEND或者SUBSCRIBE命令去发送和订阅消息,destination头部用来描述消息发送到哪里以及谁应该接收消息,下面的消息结构是客户端订阅股票行情的例子,如下:
SUBSCRIBE
id:sub-1
destination:/topic/price.stock.*
下面的消息结构是客户端发送交易请求的例子,如下:
SEND
destination:/queue/trade
content-type:application/json
content-length:44{"action":"BUY","ticker":"MMM","shares",44}
STOMP服务端可以使用MESSAGE 命令广播消息给所有的订阅者,下面的例子为广播股票行情消息给所有消息订阅者。
MESSAGE
message-id:nxahklf6-1
subscription:sub-1
destination:/topic/price.stock.MMM{"ticker":"MMM","price":129.45}
3、使用STOMP的好处
在Spring中使用STOMP与原生WebSockets相比提供了更加丰富的编程模型,下面是使用STOMP的优点:
- 不需要发明自定义消息协议和消息格式。
- 在Spring中,STOMP客户端,包括Java客户端都可用。
- 可使用其它消息代理管理消息订阅和广播,如
RabbitMQ,ActiveMQ等支持STOMP协议的中间件。 - 应用逻辑处理入口可以像Spring MVC一样统一在
@Controller实例内,同时消息可以基于STOMP头部消息进行路由,而不是直接用WebSocketHandler处理原生WebSocket消息。 - 可以基于STOMP目的地和消息类型使用
Spring Security对消息进行安全传输。
三、代码示例
1、Maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
备注:这里我就简单用Thymeleaf作模板引擎,为了方便调试在application.yml中将
spring.thymeleaf.cache设为false来禁用模板缓存。
2、开启WebSocket消息代理
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/websocket") // WebSocket握手端口.addInterceptors(new HttpSessionHandshakeInterceptor()).setAllowedOriginPatterns("*") // 设置跨域.withSockJS(); // 开启SockJS回退机制}@Overridepublic void configureWebSocketTransport(WebSocketTransportRegistration registry) {// 这里我们设置入站消息最大为8Kregistry.setMessageSizeLimit(8 * 1024);}@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {registry.setApplicationDestinationPrefixes("/app") // 发送到服务端目的地前缀.enableSimpleBroker("/topic");// 开启简单消息代理,指定消息订阅前缀}}
备注:
- 关于SockJS的介绍请参考上篇文章 WebSocket的那些事(1-概念篇)最后部分。
setApplicationDestinationPrefixes的意思是以目的地以/app开头的消息将会被路由到Controller实例中的方法进行处理。enableSimpleBroker将会启用一个内置的内存消息代理,用于订阅、广播和路由消息目的地到以/topic开头代理中。
3、控制器
@Slf4j
@Controller
public class GreetingController {@GetMapping("/page/greeting")public ModelAndView turnToGreetingPage() {return new ModelAndView("/greeting");}@MessageMapping("/greeting")public String sayGreeting(String name) {log.info("Message received: {}", name);return "Hello, " + name;}
}
4、前端页面greeting.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>greeting</title><script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script><style>#mainWrapper {width: 600px;margin: auto;}</style>
</head>
<body>
<div id="mainWrapper"><div id="msgWrapper"><p style="vertical-align: top">发送的消息:</p><textarea id="msgSent" style="width: 400px;height: 100px"></textarea><p style="vertical-align: top">收到的消息:</p><textarea id="msgReceived" style="width: 400px;height: 100px"></textarea></div><div style="margin-top: 5px;"><button onclick="connect()">连接</button><button onclick="sendMessage()">发送消息</button><button onclick="disconnect()">断开连接</button></div>
</div>
<script type="text/javascript">$(() => {$('#msgSent').val('');$("#msgReceived").val('');});let stompClient = null;// 连接服务器const connect = () => {const ws = new SockJS('http://localhost:8080/websocket');stompClient = Stomp.over(ws);stompClient.connect({}, () => {$("#msgReceived").val('Connected to websocket server!');stompClient.subscribe('/topic/greeting', function (message) {console.log(`Received message: ${message.body}`);$("#msgReceived").val(message.body);});});}// 断连const disconnect = () => {stompClient.disconnect(() => {$("#msgReceived").val('Disconnected from WebSocket server');});}// 发送消息,这里直接发的是文本const sendMessage = () => {stompClient.send('/app/greeting', {}, $('#msgSent').val());}
</script>
</body>
</html>
备注:
- greeting.html为
Thymeleaf模板页面,文件直接放在类路径templates目录下即可.- 这里我们选用了
SockJS去连接服务端,为什么使用SockJS请参考 WebSocket的那些事(1-概念篇),同时注意协议名称是http而不是ws。
四、测试
浏览器输入http://localhost:8080/page/greeting即可跳转到我们的页面,如下:

1、连接服务端
点击连接按钮后,我们发现已经与服务端成功建立连接。我们可以观察到客户端发送了两条命令,一条是Connect建立连接命令,另一条是连接建立成功后的SUBSCRIBE命令,用来订阅目的地以/topic/greeting开头的消息。

2、发送消息
点击发送按钮发送消息,可以看到服务端也返回了Hello, Nick的回复消息。

备注:我们可以看到客户端发送了一条
SEND命令,目的地为/app/greeting,内容长度为4个字节。同时服务端回复了一条MESSAGE命令,这条命令的意思是广播消息给所有订阅/topic/greeting的客户端。
五、STOMP消息传播流程
一旦STOMP端点暴露,Spring应用对于连接的客户端就变成了STOMP代理,下面我们简单介绍一下服务端消息传播流程。

上面的图展示了三种消息渠道:
clientInboundChannel: 客户端消息入站通道,用来传递WebSocket客户端接收的消息。clientOutboundChannel: 客户端消息出站通道,用来发送服务端消息给WebSocket客户端。brokerChannel: 消息代理通道,用来在服务层传递消息给消息代理。
目的地以/app/a开头的消息会通过clientInboundChannel路由到MessageHandler消息处理器进行处理,然后再将消息通过brokerChannel发送到SimpleBroker中。
目的地以/topic/a开头的消息会通过clientInboundChannel直接路由到SimpleBroker中进行处理。
上图中的SimpleBroker实际上是Spring基于内存的内置消息代理,实际上Spring也支持集成其它支持STOMP协议的MQ,如ActiveMQ、RabbitMQ等,集成外部消息代理的消息传播流程图如下:

从上图中,我们可以看到StompBrokerRelay会和外部消息代理进行通信,通过enableStompBrokerRelay即可以集成外部消息代理,关于集成外部消息代理的例子和细节我们在后面的章节在讨论。
六、结语
这节我们简单介绍了STOMP协议、Spring中对WebSocket的STOMP支持以及具体的代码集成示例。
下节我们将会具体介绍@Controller控制器中相关消息注解的使用示例和细节,如@MessageMapping、@SubscribeMapping、@MessageExceptionHandler、@SendTo、@SendToUser等。

相关文章:
WebSocket的那些事(3-STOMP实操篇)
目录 一、序言二、STOMP详解1、STOMP简单介绍2、STOMP协议内容3、使用STOMP的好处 三、代码示例1、Maven依赖2、开启WebSocket消息代理3、控制器4、前端页面greeting.html 四、测试1、连接服务端2、发送消息 五、STOMP消息传播流程六、结语 一、序言 上节中我们在 WebSocket的…...
《花雕学AI》WeTab+ChatGPT:让浏览器变成你的智能助手
引言: 浏览器是我们日常使用的最重要的工具之一,它可以帮助我们获取信息、娱乐、学习、工作等。但是,传统的浏览器往往不能满足我们的个性化需求,也不能给我们提供智能化的服务。那么,有没有一种浏览器可以让我们的体…...
MySQL 字段为 NULL 的5大坑,大部分人踩过
数据库字段允许空值(null)的问题,小伙伴你遇到过吗? 在验证问题之前,我们先建一张测试表及测试数据。 构建的测试数据,如下图所示: 有了上面的表及数据之后,我们就来看当列中存在 NULL 值时,究…...
Android SystemUI篇(二)
目录 一、简介 二、SystemUI的架构 三、SystemUI的主要组件 四、SystemUI的主要功能 五、SystemUI的自定义和定制 六、SystemUI的性能优化 一、简介 SystemUI是Android操作系统的一个关键组件,主要负责管理和提供用户界面的核心元素,如状态栏、导航…...
第六讲:“声音”写具体
爸爸又打呼了!“呼噜一呼噜一像一股巨浪腾空而起,以每秒八十米的速度向上冲刺,力图掀开天花板,掀翻整座住宅楼;“呼噜一一呼噜一-”,像一台轰鸣的坦克在穿行,床垫在抖动,吊灯在摇晃,墙灰在簌籁(…...
Unity 向量
向量的加减法本文就不再赘述了,本文侧重介绍脚本中的向量写法 一、向量的数乘 定义:k(x,y,z)(kx,ky,kz) 若向量长度为L,k取1/L,就恰好能让原向量长度变成1,变成了单位向量,这称为向量的标准化 。 由于长度…...
Apache Tomcat AJP协议文件读取与包含
永远也不要忘记能够笑的坚强,就算受伤,我也从不彷徨。 0x01.漏洞情况分析 Tomcat是Apache软件基金会Jakarta 项目中的一个核心项目,作为目前比较流行的Web应用服务器,深受Java爱好者的喜爱,并得到了部分软件开发商的…...
实验10 人工神经网络(1)
1. 实验目的 ①理解并掌握误差反向传播算法; ②能够使用单层和多层神经网络,完成多分类任务; ③了解常用的激活函数。 2. 实验内容 ①设计单层和多层神经网络结构,并使用TensorFlow建立模型,完成多分类任务…...
OPPO关停哲库业务,工程师造芯何去何从?
5月12日(上周五),新浪科技从OPPO处了解到,OPPO将终止ZEKU业务。3000多人团队突然原地解散,网上唏嘘声一片! ZEKU最初成立于2019年,是OPPO的全资子公司,欧加集团百分之百注资成立。总…...
面试被问麻了....
前几天组了一个软件测试面试的群,没想到效果直接拉满,看来大家对面试这块的需求还是挺迫切的。昨天我就看到群友们发的一些面经,感觉非常有参考价值,于是我就问他还有没有。 结果他给我整理了一份非常硬核的面筋,打开…...
AspNetCore中的配置文件详解
1 配置文件 程序开发中,有些信息是要根据环境改变的,比如开发环境的数据库可能是本地数据,而生产环境下需要连接生产数据库,我们需要把这些信息放到程序外面,在程序运行时通过读取这些外部信息实现不改变程序代码适应…...
实时更新天气微信小程序开发
1.新建一个天气weather项目 2.在app.json中创建一个路由页面 当我们点击保存的时候,微信小程序会自动的帮我们创建好页面 3.在weather页面上书写我们的骨架 4.此时我们的页面很怪,因为没有给它添加样式和值。此时我们给它一个样式。(样式写在…...
css渐变
线性渐变 liner-gradient属性值用来设置线性渐变,第一个参数值是方向,默认是从上往下,往后就是渐变颜色的种类。 background-image:liner-gradient(方向,颜色1,颜色2...) .box {display: flex;width: 400px;height: …...
《斯坦福数据挖掘教程·第三版》读书笔记(英文版) Chapter 2 MapReduce and the New Software Stack
来源:《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT Chapter 2 MapReduce and the New Software Stack Computing cluster means large collections of commodity hardware, including conventional processors (“compute nodes”) connected by Ethernet …...
HTML零基础快速入门(详细教程)
1,HTML代码特点 <html><head></head><body>hello world!</body> </html>HTML代码有以下特点: html代码是通过标签来组织的,而标签是由尖括号< >组织的,也可被叫作元素(ele…...
Kubernetes第5天
第七章 Service详解 本章节主要介绍kubernetes的流量负载组件:Service和Ingress。 Service介绍 在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着…...
RK3568平台开发系列讲解(调试篇)debugfs 分析手段
🚀返回专栏总目录 文章目录 一、enable debugfs二、debugfs API三、使用示例沉淀、分享、成长,让自己和他人都能有所收获!😄 📢Linux 上有一些典型的问题分析手段,从这些基本的分析方法入手,你可以一步步判断出问题根因。这些分析手段,可以简单地归纳为下图: 从这…...
【Spring框架全系列】SpringBoot配置日志文件
🍧🍧哈喽,大家好,我是小浪。那么上篇博客我们学习了SpringBoot配置文件的相关操作,本篇博客我们将学习一个新的知识点,SpringBoot日志文件。🖥🖥 📲目录 一、日志是什么…...
事务 ---MySQL的总结(六)
事务 多进程进行并改变同一个数据,如果没有进行版本控制,就会出现数据不确定的问题,为此引入了事务的概念。可以进行数据回滚,解决潜在的问题。 事务的概念 一组的DML组成,这一些的DML要么同时成功,要么同…...
22 标准模板库STL之容器适配器
概述 提到适配器,我们的第一印象是想到设计模式中的适配器模式:将一个类的接口转化为另一个类的接口,使原本不兼容而不能合作的两个类,可以一起工作。STL中的容器适配器与此类似,是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能和接口。之所…...
你还在使用HAL_Delay吗
HAL_Delay 是STM32HAL库提供的毫秒级延时函数, 相信所有STM32开发人员都对它非常的熟悉, 那么你曾经或者是现在是否还在频繁的使用HAL_Delay呢? 现在的你是否还记得自己点亮的第一颗Led灯呢?看下面代码:void Led_Flicker(void){Led_On();HAL_Delay(500);Led_Off();HAL_Delay(…...
Joy-Con Toolkit终极指南:免费解决手柄漂移和自定义你的Switch手柄
Joy-Con Toolkit终极指南:免费解决手柄漂移和自定义你的Switch手柄 【免费下载链接】jc_toolkit Joy-Con Toolkit 项目地址: https://gitcode.com/gh_mirrors/jc/jc_toolkit Joy-Con Toolkit是一款功能强大的开源工具,专门为Nintendo Switch玩家设…...
【AI写代码】怎么用AI写代码
1、思路 先找到后端应该的脚本,让AI给编写对应的接口规范手册2、拖动接口规范手册,让AI给编写对应的接口测试用例 根据XXX接口规范手册,编写pytest框架的自动化测试用例...
3分钟搞定城通网盘限速:免费直连解析工具完整指南
3分钟搞定城通网盘限速:免费直连解析工具完整指南 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 你是否曾经因为城通网盘的限速下载而烦恼?面对几十KB/s的下载速度,…...
网盘直链下载助手:2025年最完整的跨平台云盘下载解决方案
网盘直链下载助手:2025年最完整的跨平台云盘下载解决方案 【免费下载链接】baiduyun 油猴脚本 - 一个免费开源的网盘下载助手 项目地址: https://gitcode.com/gh_mirrors/ba/baiduyun 在当今数据驱动的时代,云存储服务已成为个人和企业数据管理的…...
Jimeng AI Studio效果展示:Z-Image-Turbo生成3D渲染风格图像
Jimeng AI Studio效果展示:Z-Image-Turbo生成3D渲染风格图像 1. 惊艳的3D渲染效果展示 Jimeng AI Studio基于Z-Image-Turbo引擎,在3D渲染风格图像生成方面展现出了令人印象深刻的能力。这个轻量级工具不仅生成速度快,更重要的是能够产出具有…...
Phi-4-mini-reasoning惊艳效果展示:高精度数学推导+代码生成对比实测
Phi-4-mini-reasoning惊艳效果展示:高精度数学推导代码生成对比实测 1. 开篇:小模型的大智慧 Phi-4-mini-reasoning这款仅有3.8B参数的轻量级开源模型,正在重新定义我们对小型语言模型能力的认知。专为数学推理、逻辑推导和多步解题等强逻辑…...
从零到一:在Rocky Linux 9.6上源码编译部署MySQL 8.0全记录
1. 环境准备:打造坚实的编译基础 在Rocky Linux 9.6上源码编译MySQL 8.0,就像盖房子需要打好地基。我遇到过不少新手直接开干,结果被各种依赖问题卡住。咱们先花10分钟把基础环境收拾妥当,后面能省下几小时的排错时间。 首先确保你…...
推荐系统中的个性化算法与效果评估
推荐系统中的个性化算法与效果评估 在信息爆炸的时代,推荐系统已成为互联网平台提升用户体验的关键技术。个性化算法通过分析用户行为、兴趣和偏好,为用户精准匹配内容,而效果评估则衡量算法的实际表现。本文将围绕推荐系统中的个性化算法与…...
智能规约员中的业务规则封装与验证逻辑
智能规约员中的业务规则封装与验证逻辑 在数字化时代,企业需要高效处理复杂的业务规则以确保运营合规性和决策准确性。智能规约员通过将业务规则封装为可复用的逻辑单元,并结合自动化验证技术,显著提升了规则管理的灵活性与可靠性。本文将深…...
