Spring WebSocket @SendToSession: send message to specific session
No need to create specific destinations, it's already done out of the box as of Spring 4.1 (see SPR-11309).
Given users subscribe to a /user/queue/something
queue, you can send a message to a single session with:
As stated in the SimpMessageSendingOperations Javadoc, since your user name is actually a sessionId, you MUST set that as a header as well otherwise the DefaultUserDestinationResolver
won't be able to route the message and will drop it.
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor
.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
messagingTemplate.convertAndSendToUser(sessionId,"/queue/something", payload,
headerAccessor.getMessageHeaders());
You don't need users to be authenticated for this.
It is very complicated and in my opinion, isn't worth it. You need to create a subscription for every user (even unauthenticated ones) by their session id.
Let's say that every user subscribes to a unique queue only for him:
stompClient.subscribe('/session/specific' + uuid, handler);
On the server, before the user subscribes you will need to notify and send a message for the specific session and save to a map:
@MessageMapping("/putAnonymousSession/{sessionId}")
public void start(@DestinationVariable sessionId) throws Exception {
anonymousUserSession.put(key, sessionId);
}
After that, when you want to send message to the user you will need to:
messagingTemplate.convertAndSend("/session/specific" + key);
But I don't really know what you are trying to do and how you will find the specific session (who is anonymous).
You need to simply add the session id in
Server Side
convertAndSendToUser(sessionId,apiName,responseObject);
Client Side
$stomp.subscribe('/user/+sessionId+'/apiName',handler);
Note:
Dont forget to add '/user'
in your end point in server side.
I was struggling with the same problem and presented solution didnt work for me, therefore I had to take different approach:
- modify web socket config so user will be identified by session ID:
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-endpoint")
.setHandshakeHandler(new DefaultHandshakeHandler() {
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession();
return new Principal() {
@Override
public String getName() {
return session.getId();
}
};
} else {
return null;
}
}
}).withSockJS();
}
- send message to that session id (without headers):
simpMessagingTemplate.convertAndSendToUser(sessionId, "/queue", payload);