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);