我正在使用Spring Websocket和STOMP,以及Simple Message Broker。在我的@Controller
中,我使用了基于方法级别的@SubscribeMapping
注解,它应该订阅客户端到一个主题,这样客户端就可以接收到该主题的消息。假设客户端订阅了主题"chat":
stompClient.subscribe('/app/chat', ...);
由于客户端订阅的是"/app/chat"而不是"/topic/chat",因此该订阅将转到使用@SubscribeMapping
映射的方法:
@SubscribeMapping("/chat")
public List getChatInit() {
return Chat.getUsers();
}
这里是Spring参考文档内容:
默认情况下,@SubscribeMapping方法的返回值会直接作为消息发送回连接的客户端,而不经过代理。这对于实现请求-响应消息交互非常有用;例如,在初始化应用程序UI时获取应用程序数据。
好的,这正是我想要的,但只是部分地!在订阅后发送一些初始数据,很好。但是关于订阅呢?在我看来,这里发生的事情就像一个请求-响应,类似于服务。订阅只是被消费了。如果是这种情况,请帮我澄清一下。
- 如果代理没有参与,客户端是否已经订阅到某个位置了?
- 如果我以后想向“聊天”订阅者发送一些消息,客户端会收到吗?看起来并不是这样。
- 谁真正实现了订阅?代理还是其他人?
如果客户端没有被订阅到任何位置,我想知道为什么我们称之为“订阅”;因为客户端只接收一条消息,而不是未来的消息。
编辑:
为了确保订阅已经实现,我尝试了以下操作:
服务器端:
配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").withSockJS();
}
}
控制器:
@Controller
public class GreetingController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
System.out.println("inside greeting");
return new Greeting("Hello, " + message.getName() + "!");
}
@SubscribeMapping("/topic/greetings")
public Greeting try1() {
System.out.println("inside TRY 1");
return new Greeting("Hello, " + "TRY 1" + "!");
}
}
客户端:
...
stompClient.subscribe('/topic/greetings', function(greeting){
console.log('RECEIVED !!!');
});
stompClient.send("/app/hello", {}, JSON.stringify({ 'name': name }));
...
我希望发生的事情:
- 当客户端订阅'
/topic/greetings
'时,执行try1
方法。 - 当客户端向'
/app/hello
'发送消息时,应该收到问候消息,即@SendTo
'/topic/greetings
'。
结果:
如果客户端订阅了
/topic/greetings
,则无法捕获try1
方法。当客户端向'
/app/hello
'发送消息时,执行了greeting
方法,客户端收到了问候消息。因此我们知道它已正确订阅'/topic/greetings
'。但是请记住问题1失败了。尝试了一些方法后,当客户端订阅了
'/app/topic/greetings'
时,即使用/app
前缀(这可以通过配置理解)。现在问题1已经解决,但是问题2失败了:当客户端向'
/app/hello
'发送消息时,确实执行了greeting
方法,但是客户端没有收到问候消息。(因为现在客户端可能订阅了以'/app
'为前缀的主题,这是不希望的。)
所以,我得到的是我想要的1或2个,但不是这两个一起。
- 如何使用此结构(正确配置映射路径)实现这一点?
答案不在提供的文本中。
/topic/chat.participants
的订阅,类似于消息映射转发到相应的代理目标。但是我没有看到这种情况发生,据我所知,客户端必须单独订阅/topic/chat.participants
。 - rainerfrey