如何在 Spring 引导中使用 websocket 主题中的选择器发送消息

How to send messages with selectors in websocket topic in Spring Boot

澄清:

感谢@JustinBertram 的评论,我意识到这个问题没有意义。

STOMP 协议本身不支持选择器,您必须使用实现它的代理,例如 ActiveMQ。 STOMP 支持 headers,代理可以使用它们来通过选择器过滤消息。

就我而言,我没有使用任何代理,只是前端使用 Angular + Stomp + SocksJS,后端使用 Spring Boot,所以我不能使用选择器。

STOMP 协议的文档没有让我清楚这一点,我感到很困惑。请参阅这些参考资料:

the specification:

Stomp brokers may support the selector header which allows you to specify an SQL 92 selector on the message headers which acts as a filter for content based routing.

this article:

The subscribe() method takes an optional headers argument to specify additional headers when subscribing to a destination:

var headers = {ack: 'client', 'selector': "location = 'Europe'"};
client.subscribe("/queue/test", message_callback, headers);

The client specifies that it will handle the message acknowledgement and is interested to receive only messages matching the selector location = 'Europe'.


我正在 Spring Boot 中实现一个后端。对于 two-way 与前端的通信,我使用 stomp over websockets。

我关注了this Spring Boot + Angular example

可以,但是我的一个要求是后端必须发送带有选择器的消息,以便前端订阅一个主题并且只接收过滤后的数据,以避免实时数据的性能问题。

{ 'selector': "location = 'Europe'" }

为此,我试图让后端发送带有选择器的消息,但我做不到。

我已经按照 this article 实现了带有选择器的前端并且它工作正常,只有后端有问题

我尝试使用 @SendTo 注释,但根据文章,它似乎没有任何参数:

@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
    Thread.sleep(1000);
    return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
}

我也试过 MessagingTemplate,但我不知道如何在 header:

中设置选择器属性

http://assets.spring.io/wp/WebSocketBlogPost.html

MessageSendingOperations<String> messagingTemplate;

messagingTemplate.convertAndSend(destination, quote);

非常感谢任何帮助,我已经阅读了很多文章和文档,但我没有找到任何特别讨论此问题的解决方案。

latest version of the STOMP specification 不包含任何关于 selector 及其语法的特定声明,因为关于此处支持的内容,这实际上取决于代理实施。规范现在只声明:

STOMP servers MAY support additional server specific headers to customize the delivery semantics of the subscription. Consult your server's documentation for details.

ActiveMQ 5.x 和 ActiveMQ Artemis 等代理支持 selector STOMP header 并且 selector 的语法和行为基于 JMS select或

JMS 中的选择器用于 selecting 消费消息,由消费客户端配置。发送消息时不能设置selector。

JMS select或 select 基于 header 或消息属性的消息,尽管一些实现超出了这一点并允许 selecting 基于消息本身的内容。因此,如果您想在消费者上使用 select 或 location = 'Europe',那么您应该在消息以名称 location 和值发送时在消息上设置 header共 Europe.

convertAndSend 方法被重载并提供了两种设置 header:

的方法

嗯,可以将 JMS 的选择器与 Spring(引导)Websocket 和 STOMP 客户端一起使用。我找到了原生方式。

关键是选择器应用于org.springframework.messaging.Message实例它使用Spring的Spel 应用条件的语言(不是 JMS SQL-like)。

所以使用默认的 SimpMessagingTemplate,在后端你可以像这样发送 header 个变量:

this.messagingTemplate.convertAndSend(
    "/topic/something", //your destination
    payload, //any kind of payload (body)
    Map.of("id", 1) //header with key/value
);

在前端,要输入将由 org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry.filterSubscriptions 计算的选择器,您必须将 Stomp/WebSockets header 声明为:

{"selector": "headers['nativeHeaders']['id'][0] == '999'"}

是的,这很糟糕,但它确实有效。

由于默认的 MessageGenericMessage,header 将在名为 "nativeHeaders" 的新密钥中进行处理。 ['key'],[0] and == 是 Spring 的 Spel 语法。

请继续在后端过滤您的消息,而不是在前端!