禁止在 SimpMessagingTemplate 的 convertAndSendToUser 方法中广播

Disallow broadcast in convertAndSendToUser method in SimpMessagingTemplate

我正在使用 Spring websocket 实现。向客户端发送消息有两种方式:

1) 使用 @SendToUser 注释
2)使用SimpMessagingTemplate

convertAndSendToUser方法

@SendToUser 接受一个名为 broadcast 的布尔参数,如果设置为 false,则将消息发布到当前会话。有没有办法让我在 SimpMessagingTemplate.

中有这种行为

如果我们查看 SendToMethodReturnValueHandler 源代码,我们会看到:

if (broadcast) {
    this.messagingTemplate.convertAndSendToUser(user, destination, returnValue);
}
else {
    this.messagingTemplate.convertAndSendToUser(user, destination, returnValue, createHeaders(sessionId));
}

因此,您的用例需要的只是使用重载的 convertAndSendToUser 并提供带有 `sessionId:

Map
messagingTemplate.convertAndSendToUser(user, destination, payload, 
           Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, sessionId))

上面的答案对我不起作用。事实证明,Spring 4.1.4 需要一些稍微不同的东西。

对我来说最干净的方式如下所示:

SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create();
headerAccessor.setSessionId(cmd.getSessionId());
headerAccessor.setLeaveMutable(true);
MessageHeaders messageHeaders = headerAccessor.getMessageHeaders();

messagingTemplate.convertAndSendToUser(cmd.getPrincipal().getName(),
       "/queue/responses", ret, messageHeaders);

另一种可行的方法是向发送到 SimpMessagingTemplate.convertAndSendToUser() 的映射显式添加一个 "nativeHeaders" 值。但是,这种方式似乎过于依赖实现细节:

Map<String, Object> headers = new HashMap<>();
headers.put("nativeHeaders", new HashMap<String, Object>());
headers.put(SimpMessageHeaderAccessor.SESSION_ID_HEADER, cmd.getSessionId());

messagingTemplate.convertAndSendToUser(cmd.getPrincipal().getName(),
        "/queue/responses", ret, headers);

"offending code" 使设置 "simpSessionId" header 而地图中的其他任何东西都不起作用是在 SimpMessagingTemplate.processHeaders() 和 MessageHeaderAccessor.getAccessor(MessageHeaders , Class requiredType).

Spring 没有明确的文档,我尝试了很多不同的方法,只有下面的代码适合我。

SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create();
accessor.setHeader(SimpMessageHeaderAccessor.SESSION_ID_HEADER, sessionId);
messagingTemplate.convertAndSendToUser(sessionId, destination, payload, accessor.getMessageHeaders());

通过 SimpMessagingTemplate

发送给用户的最简单方法
@Autowired
private SimpMessagingTemplate messagingTemplate;

@MessageMapping("/getHello")
public void sendReply( MessageHeaders messageHeaders, @Payload String message, @Header(name = "simpSessionId") String sessionId){
        messagingTemplate.convertAndSendToUser(sessionId, "/queue/hello", "Hello "+ message, messageHeaders);
}