🔥 Solon 之 STOMP
一、STOMP 简介
如果直接使用 WebSocket 会非常累,就像用 Socket 编写 Web 应用。没有高层级的交互协议,就需要我们定义应用间所发消息的语义,还需要确保连接的两端都能遵循这些语义。
如 HTTP 在 TCP 套接字之上添加了请求-响应模型层一样,STOMP 是在 WebSocket 之上提供了基于帧的线路格式层,用来定义消息的语义。
与 HTTP 请求和响应类似,STOMP 帧由命令、一个或多个头信息以及负载组成。像下面这段,就是发送数据的一个 STOMP 帧:
SEND transaction:tx-0 destination:/app/hello content-length:20 content-type:text/json {"message":"Hello!"}
在这个示例中,STOMP 命令是 send,表明会发送一些内容。紧接着是三个头信息:一个表示消息的的事务机制,一个用来表示消息要发送到哪里的目的地,另外一个则包含了负载的大小。然后,紧接着是一个空行,STOMP 帧的最后是负载内容。
二、服务端实现
1、启用STOMP功能
STOMP 的消息根据前缀的不同分为三种。如下,以 /app
开头的消息都可以路由到带有 @Mapping 注解的方法中;以/topic
开头的消息都会发送到 STOMP 代理中,根据你所选择的 STOMP 代理不同,目的地的可选前缀也会有所限制;以 /user
开头的消息会将消息重路由到某个用户独有的目的地上。
添加依赖
<dependency> <groupId>org.noear</groupId> <artifactId>solon-net-stomp</artifactId> </dependency>
添加端点监听,并设定 broker 目的地前缀
@ServerEndpoint("/demo") public class DemoStompBroker extends StompBroker { public DemoStompBroker() { this.setBrokerDestinationPrefixes("/topic/"); } }
2、处理来自客户端的STOMP消息
服务端处理客户端发来的 STOMP 消息,主要用的是 @Mapping
注解(和 MVC 开发一样),也可以增加 @Message
方式限有定注解。如下:
@Message //如果不加,同时匹配 http 及其它请求 @Mapping("/app/marco") @To("*:/topic/marco") public Shout greeting(Shout shout) throws Exception { log.debug("接收到消息:" + shout.getMessage()); Shout s = new Shout(); s.setMessage("Polo!"); return s; }
2.1 @Mapping
指定目的地是 /app/marco
(我们将其约定为应用的目的地前缀)。
2.2 方法接收一个 Shout 参数,因为 Solon 的执行器根据内容类型自动会将 STOMP 消息的负载转换为 Shout 对象。
2.3 尤其注意,这个处理器方法有一个返回值,这个返回值并不是返回给客户端的,而是转发给消息代理的,如果客户端想要这个返回值的话,只能从消息代理订阅。@To
注解重写了消息代理的目的地,如果不指定@To
,帧所发往的目的地会与触发处理器方法的目的地相同。
2.4 如果客户端就是想要服务端直接返回消息呢?听起来不就是HTTP做的事情!即使这样,STOMP 仍然为这种一次性的响应提供了支持,用的还是@Mapping
注解,与HTTP不同的是,这种请求-响应模式是异步的...
@Message @Mapping("/app/getShout") public Shout getShout(){ Shout shout = new Shout(); shout.setMessage("Hello STOMP"); return shout; }
3、发送消息到客户端
3.1 在应用的任意地方发送消息
使用 StompEmitter 接口,可以实现自由的向任意目的地发送消息。
@Inject private StompEmitter stompEmitter; /** * 通过 http 接口,广播消息 */ @Http @Mapping("/broadcastShout") public void broadcast(Context ctx, Shout shout) { String json = ctx.renderAndReturn(shout); //渲染数据 stompEmitter.sendTo("/topic/shouts", json); }
3.2 更多发送消息的方式
如果消息只想发送给特定的用户呢?或者发给当前用户?或者所有订阅用户?solon-net-stomp 给了两种方式来实现这种功能:
- 一种是 StompEmitter 接口的 sendTo 方法。
- 一种是 基于 @To 注解。
StompEmitter 接口 | 对应的 @To 注解 | 说明 |
---|---|---|
@To("target:destination?") | To 注解表达式(stomp 请求时有效) | |
sendToSession | @To(".:/...") 或@To(".") | 发给当前客户端订阅者 |
sendToUser | @To("user:/...") 或@To("user") | 发给特定用户订阅者 |
sendTo | @To("*:/...") 或@To("*") | 发给代理,再转发给所有订阅者 |
4、处理消息异常
在处理消息的时候,有可能会出错并抛出异常。因为STOMP消息异步的特点,发送者可能永远也不会知道出现了错误。可以调整端点监听,添加 StompListener 实现。
@ServerEndpoint("/demo") public class DemoStompBroker extends StompBroker implements StompListener{ public DemoStompBroker(){ //可选:添加鉴权监听器(此示例,用本类实现监听) this.addListener(this); this.setBrokerDestinationPrefixes("/topic/"); } @Override public void onError(StompSession session, Throwable error) { //可选:如果出错,反馈给客户端(比如用 "/user/app/errors") getEmitter().sendToSession(session, "/user/app/errors", new Message(error.getMessage())); } }
三、客户端
STOMP 可以使用 stomp.js。接口参考: https://stomp-js.github.io/api-docs/latest/classes/Client.html
1、创建连接并订阅
let stomp = new StompJs.Client({ brokerURL: "ws://127.0.0.1:8080/demo?user=user01", onConnect: function (frame) { stomp.subscribe("/topic/marco", function (message) { let obj = JSON.parse(message.body); console.log("订阅的服务端消息:" + obj.message); }); stomp.subscribe("/app/getShout", function (message) { let obj = JSON.parse(message.body); console.log("订阅的服务端应胜消息:" + obj.message); }); stomp.subscribe("/user/app/errors", function (message) { console.log("订阅的服务端返回的异常消息:" + message.body); }); } });
2、发送消息
stomp.publish({ destination: "/app/marco", headers: {"content-type": "text/json"}, body: JSON.stringify({"message": "Marco!"}) });

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
deepin 扩展全球版图,拥抱‘天空之境’玻利维亚
deepin 第 8 个海外分支社区成立啦!!! deepin 第 8 个海外分支社区成立啦!!! deepin 第 8 个海外分支社区成立啦!!! 随着 deepin 社区国际化步伐的稳健前行,我们欣喜地宣布,deepin 的第 8 个海外分支社区——玻利维亚站,现已正式成立!这也标志着 deepin 社区在南美洲的影响力得到了进一步提升,也为 deepin 的全球化征程铺设了更加坚实的基础。 deepin 玻利维亚社区:https://deepinbolivia.com/ 玻利维亚是位于南美洲西部的内陆国家,拥有丰富的文化多样性。玻利维亚有若干“世界之最”,有世界上海拔最高的首都拉巴斯,有世界上最大的高原湖泊的的喀喀湖,有著名的乌尤尼盐沼,也就是世界著名的“天空之镜”······,而现在又有最美的桌面操作系统 deepin。 玻利维亚分支站点的团队领航者,乃是一位经验丰富的 UI/UX 设计师。自2015年起,他便与 deepin 结下了不解之缘,遇见 deepin 的第一眼,便被 deepin 的美学设计理念、流畅的操作体验以及稳健的性能表现所吸引,从此他便成为了 deepin ...
- 下一篇
菜并快乐着,就是我的编程哲学
为了迎接 1024 程序员节,OSChina 开源中国新增了【家里有个程序员】栏目,记录一下 OSCer 们当前的生活,欢迎各位 OSCer 踊跃投稿呀。 投稿细则:https://my.oschina.net/u/3859945/blog/15727245 作为一个最最普通(换一种说法,就是最最底层😂)的老程序员,没有要分享的开源项目,没有要分享的技术经验,仅仅就是想分享一下写代码这个爱好如何影响我的生活。 简单来说就是代码让我变懒,懒到每天吃饭都想写个eat()来执行一下,这样就不用重复进行夹菜,张嘴、送菜、闭嘴、咀嚼、下咽这些简单动作来浪费我的时间了。写代码也不仅仅是我的爱好,我也半路出家,成了一个依靠写代码糊口的码农(挣的太少,不够养家)。 上学的时候,写代码就不是我的专业,但是也会偶尔写一写,原因就是我在大学里一直是被别人控制(可以理解为军事化管理),我想控制一下别人,而代码,可以完全控制计算机,有人喜欢打游戏,我也喜欢,但是我打游戏也有一种被游戏制作者控制的感觉。这种控制别人的感觉,在写汇编语言和嵌入式的LED程序的时候尤为明显。除了让我体验控制的快感之外,写代码还让我在...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Linux系统CentOS6、CentOS7手动修改IP地址
- 2048小游戏-低调大师作品
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2更换Tomcat为Jetty,小型站点的福音