我在heroku上运行了一个spring boot应用程序。我利用websocket在特定用户的客户端和服务器之间发送消息。我使用Spring Boot的SimpMessagingTemplate.convertAndSendToUser来发送和接收消息,当用户需要从服务器获取消息时,该方法很好用。我使用Heroku会话亲缘关系,这意味着即使我扩大了会话数量,用户和websocket仍然共享同一会话。
我需要一个用户向另一个用户发送消息时出现问题。如果两个用户都共享会话,则效果很好,但是如果消息不会通过,则效果不佳。
是否可以使用SimpMessagingTemple在不同的会话中从一个用户向另一个用户发送消息?还是我需要使用消息代理,例如Redis。
我当时正在考虑使用StringRedisTemplate实现发送消息的方法,但是不确定如何向特定用户发送消息。
private SimpMessagingTemplate messagingTemplate;
@Autowired
public MessageController(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
@MessageMapping("/secured/user-in")
public void sendToDevice(Message msg, @AuthenticationPrincipal User principal) throws Exception {
if (msg.getTo() != null) {
String email = msg.getTo();
Message out = new Message();
out.setMsg(msg.getMsg());
out.setFrom(msg.getFrom());
out.setTo(msg.getTo());
out.setSentTime(new Date());
out.setStatus(msg.getStatus());
messagingTemplate.convertAndSendToUser(email, "/secured/topic", out);
}
}
JS
function connect() {
var socket = new SockJS('/secured/user-in');
ST.stompClient = Stomp.over(socket);
var headers = {};
headers[ST.getHeader()] = ST.getToken();
ST.getStompClient().connect(headers, function (frame) {
retries = 1;
console.log('Connected: ' + frame);
ST.getStompClient().subscribe('/user/secured/topic', function (event){
var msg = JSON.parse(event.body);
showMessage(msg.msg);
});
});
}
更新1
我想我可以像here一样做类似的事情:
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor
.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
messagingTemplate.convertAndSendToUser(sessionId,"/queue/something", payload,
headerAccessor.getMessageHeaders());
但是如何获取另一个用户的会话ID,我正在使用Redis存储会话信息:@EnableRedisHttpSession
答案 0 :(得分:0)
我的术语有点混乱,我试图通过另一个dyno而不是会话将消息发送给另一个用户。
最终使用redis sub / pub。
因此,当控制器接收到消息时,该消息将发布到redis,并且redis MessageListenerAdapter会调用convertAndSendToUser方法。
@MessageMapping("/secured/user-in")
public void sendToDevice(Message msg, @AuthenticationPrincipal User principal) throws Exception {
publishMessageToRedis(msg);
}
private void publishMessageToRedis(Message message) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String messageString = objectMapper.writeValueAsString(message);
stringRedisTemplate.convertAndSend("message", messageString);
}
redis配置
@Bean
RedisMessageListenerContainer container( MessageListenerAdapter chatMessageListenerAdapter) throws URISyntaxException {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.addMessageListener(chatMessageListenerAdapter, new PatternTopic("message"));
return container;
}
@Bean("chatMessageListenerAdapter")
MessageListenerAdapter chatMessageListenerAdapter(RedisReceiver redisReceiver) {
return new MessageListenerAdapter(redisReceiver, "receiveChatMessage");
}
public class RedisReceiver {
private static final Logger LOG = LogManager.getLogger(RedisReceiver.class);
private final WebSocketMessageService webSocketMessageService;
@Autowired
public RedisReceiver(WebSocketMessageService webSocketMessageService) {
this.webSocketMessageService = webSocketMessageService;
}
// Invoked when message is publish to "chat" channel
public void receiveChatMessage(String messageStr) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Message message = objectMapper.readValue(messageStr, Message.class);
webSocketMessageService.sendChatMessage(message);
}
}
@Service
public class WebSocketMessageService {
private final SimpMessagingTemplate template;
private static final Logger LOG = LogManager.getLogger(WebSocketMessageService.class);
public WebSocketMessageService(SimpMessagingTemplate template) {
this.template = template;
}
public void sendChatMessage(Message message) {
template.convertAndSendToUser(message.getTo(), "/secured/topic", message);
}
}
解决方案基于此git repository