我在 Spring 4 中使用内置 Message Broker 和 STOMP 开发实时通知系统的WebSocket
我希望能够根据用户名向特定用户发送消息。
为了实现这一目标,我使用了convertAndSendToUser
类的org.springframework.messaging.simp.SimpMessagingTemplate
方法,如下所示:
private final MessagingTemplate messagingTemplate;
@Autowired
public LRTStatusListener(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
@Scheduled(fixedDelay=5000)
public void sendMessages(Principal principal)
messagingTemplate
.convertAndSendToUser(principal.getName(), "/horray", "Horray, " + principal.getName() + "!");
}
作为配置:
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/notifications").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue", "/user");
}
}
客户端(通过 JavaScript ),我应该通过指定用户名来订阅频道(根据另一个非常相似的问题: Sending message to specific user on Spring Websocket )。
stompClient.subscribe('/user/' + username + '/horray, ...)
这最后一点听起来很奇怪......
假设我在我的网络应用上记录为 w.white ,请订阅:
stompClient.subscribe('/user/w.white/horray, ...)
...我将能够看到发送到 w.white 的消息,这很棒......但订阅:
stompClient.subscribe('/user/j.pinkman/horray, ...)
...我也可以看到发送到 j.pinkman 的消息,但是我当前记录为 w.white 。
这是解决这个问题的方法吗?
下面是关于通过WebSocket连接的日志:
Opening Web Socket...
Web Socket Opened...
>>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
<<< CONNECTED
user-name:w.white
heart-beat:0,0
version:1.1
connected to server undefined
Connected: CONNECTED
version:1.1
heart-beat:0,0
user-name:w.white
>>> SUBSCRIBE
id:sub-0
destination:/topic/lrt
>>> SUBSCRIBE
id:sub-1
destination:/user/lrt
答案 0 :(得分:20)
我找到了解决方案。
首先,重要的是要知道/user
频道已由 Spring STOMP 管理,顺便说一下,不需要注册。
所以:
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue");
}
然后,我将目标频道设置为/queue/horray
:
@Scheduled(fixedDelay=5000)
public void sendMessages(Principal principal)
messagingTemplate
.convertAndSendToUser(principal.getName(), "/queue/horray", "Horray, " + principal.getName() + "!");
}
最后,在客户端:
stompClient.subscribe('/user/queue/horray', '...');
现在,它运作正常!根据安全上下文提取的Principal
,消息仅发送给指定的收件人。
答案 1 :(得分:7)
由于我的应用程序上的用户未经过身份验证,我只是使用会话ID来区分各种主题
在服务器上:
template.convertAndSend("/topic/warnings/" + sessionId, ...)
客户端非常简单
stompClient.subscribe('/topic/warnings/${pageContext.session.id}', ...
也许不是最干净的方式,但它有效,如果没有身份验证,我无法使用/用户频道