首页 > 其他分享 >Solon 之 STOMP

Solon 之 STOMP

时间:2024-10-23 21:34:26浏览次数:7  
标签:Solon stomp Shout STOMP 消息 message app

一、STOMP 简介

如果直接使用 WebSocket 会非常累,就像用 Socket 编写 Web 应用。没有高层级的交互协议,就需要我们定义应用间所发消息的语义,还需要确保连接的两端都能遵循这些语义。

如 HTTP 在 TCP 套接字之上添加了请求-响应模型层一样,STOMP 是在 WebSocket 之上提供了基于帧的线路格式层,用来定义消息的语义。

与 HTTP 请求和响应类似,STOMP 帧由命令、一个或多个头信息以及负载组成。像下面这段,就是发送数据的一个 STOMP 帧:

SEND
transaction:tx-0
destination:/app/hello
content-length:20

{"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 one rror(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!"})
});

标签:Solon,stomp,Shout,STOMP,消息,message,app
From: https://www.cnblogs.com/noear/p/18498408

相关文章

  • flutter的custompaint组件示例6
    这段代码是一个Flutter应用程序,它创建了一个动态的艺术效果,其中包含随机颜色的点在屏幕上不断更新位置。import'package:flutter/material.dart';import'dart:math';voidmain(){runApp(MyApp());}classMyAppextendsStatelessWidget{@overrideWidget......
  • flutter的custompaint组件示例5
    这段代码是一个简单的Flutter应用程序,它创建了一个可拖动的自定义圆角矩形组件。import'package:flutter/material.dart';voidmain(){runApp(MyApp());}classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){return......
  • Solon 3.0 新特性:HttpUtils 了解一下
    Solon3.0引入一个叫HttpUtils小插件,这是一个简单的同步HTTP客户端,基于URLConnection适配(也支持切换为OkHttp适配)。使得编写HTTP客户端代码更加直观和易于阅读。使用URLConnection适配时(大小为40KB左右)。默认使用OkHttp适配时(大小为3.1MB左右)。当引入okhtt......
  • Solon-Boot 与 SpringBoot 的概念不同
    平常我们是拿Solon生态与SpringBoot生态作比较。而非Solon-Boot(仅是功能模块)与SpringBoot生态,但这两名字太容易让人误解了。Solon-BootSolon-Boot仅表示Solon的“服务端“启动模块组(相当于Solonserverbootstrap)。它是个“功能性”模块划分概念,跟Solon-Data,So......
  • Solon 3.0 新特性:SqlUtilsqn
    Solon3.0引入了新的SqlUtils用于数据库基础操作,SqlUtils是对JDBC较为原始的封装,极为反朴归真。特性有:支持事务管理支持多数据源支持流式输出支持批量执行支持存储过程一、概述SqlUtils是一个轻量的数据库操作框架,简单灵活,易于阅读和维护,支持编写复杂的SQL。对于......
  • Solon 3.0 新特性:SqlUtils
    Solon3.0引入了新的SqlUtils用于数据库基础操作,SqlUtils是对JDBC较为原始的封装,采用了UtilsAPI的风格,极为反普归真。特性有:支持事务管理支持多数据源支持流式输出支持批量执行支持存储过程一、概述SqlUtils是一个轻量的数据库操作框架,采用UtilsAPI风格,简......
  • QT| “无法粘贴窗口部件”错误以及customplot
    “无法粘贴窗口部件”错误以及customplot“无法粘贴窗口部件”错误customplot下载添加到项目中使用QCustomPlot常用的代码“无法粘贴窗口部件”错误情景:使用QT设计界面,很多部分比较类似,可以复制另一个界面的ui,但是粘粘的时候会报错“无法粘贴窗口部件”。错误提示:......
  • QCustomPlot QCPBars横向柱状图示例
    #include"qcustomplot.h"intmain(intargc,char*argv[]){QApplicationa(argc,argv);QCustomPlotcustomPlot;customPlot.resize(700,500);customPlot.show();QCPAxis*keyAxis=customPlot.yAxis;QCPAxis*valueAxis=......
  • QCustomPlot QCPBars纵向柱状图示例
    #include"qcustomplot.h"intmain(intargc,char*argv[]){QApplicationa(argc,argv);QCustomPlotcustomPlot;customPlot.resize(700,500);customPlot.show();QCPAxis*keyAxis=customPlot.xAxis;QCPAxis*valueAxis=......
  • QCustomPlot绘制股票曲线,去除中间休市时间
    QCPAxis中增加两个函数,设置x轴的值和标签映射关系,要把中午午休的时间去掉; voidsetTickVector(QVector<double>tickVector){mTickVector=tickVector;};voidsetTickLabels(QVector<QString>tickLabel){mTickVectorLabels=tickLabel;}voidNGraph::SetXTimeLab......