Spring Stomp #SubscribeMapping("/user/...") with User Destination doesn't work - spring

I need to react on a user destination subscription.
Example:
A user subscribes to /user/messages, because he wants to receive all incoming messages. Now I'd like to look up any messages for this user, which were created while he was offline, and then send them to that user.
Working code:
Client code:
stompClient.subscribe('/user/messages', function(msg){
alert(msg.body);
});
Server code:
template.convertAndSendToUser(p.getName(), "/messages", "message content");
What I need:
It seems like it's not possible to catch an user destination subscription on server side, i.e.:
#SubscribeMapping("/user/messages")
public void test(Principal p) {
sendMessagesThatWereReceivedWhileUserWasOffline();
}
What I tried:
#SubscribeMapping("/messages")
public void test(Principal p) { ... }
This works, if the client subscribes to /app/messages, but it won't get called for /user/messages.
My Configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/queue", "/topic");
registry.setUserDestinationPrefix("/user");
}
#Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
return true;
}
// all other methods left empty
}
Using Spring 4.1.
I can't imagine that this isn't possible. What have I missed / done wrong?
Thank you :)

Define the user prefix also as an application prefix, and you'll then be able to map the subscription in your controller. Configuration:
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app", "/user");
registry.enableSimpleBroker("/queue", "/topic");
registry.setUserDestinationPrefix("/user");
}
Controller:
#SubscribeMapping("/messages")
public void test(Principal p) {
sendMessagesThatWereReceivedWhileUserWasOffline();
}

Related

There is an endpoint connection error problem implementing the websocket with spring boot

This is my WebSocketConfig.
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/pub");
registry.enableSimpleBroker("/sub");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket").setAllowedOriginPatterns("*").withSockJS();
}
}
This is my SocketController:
#Controller
public class SocketController {
#MessageMapping("/comm/message")
#SendTo("/sub/test")
public Message message(Message message) {
return message;
}
}
I am testing the socket through Chrome's Web Socket Test Client and Advanced Rest Client, but my connection endpoint ws://localhost:8080/socket returns the error.
Is there anything I set wrong?
connecting try tool and endPoint
return message

How to connect websocket with a mobile application?

I need for a mobile application to add websocket to the backend for chat implementation. I found an example https://github.com/callicoder/spring-boot-websocket-chat-demo, but here the chat is not for a mobile application, I don’t quite understand how to request a chat? should add api, but where?
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
}
I have an addEndpoint, should I write api in it?
Since my application does not work with the browser, how to replace .withSockJS ()?
#RestController
#RequestMapping(name = "api/chat")
public class ChatController {
#MessageMapping("/chat.sendMessage")
#SendTo("/topic/public")
public ChatMessage sendMessage(#Payload ChatMessage chatMessage) {
return chatMessage;
}
#SendTo("/topic/public")
public ChatMessage addUser(#Payload ChatMessage chatMessage,
SimpMessageHeaderAccessor headerAccessor) {
headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
return chatMessage;
}
}
or the data should come through this api?
I do not understand how to receive data in websocket via api from a mobile application in order to save it

Large messages failing on Stomp Controller in Spring Boot

I have a stomp controller in a spring boot application, When ever i send a message which exceeds 256kb it fails to enter the controller. I don't see any error messages. Is there any setting where I can configure it to allow larger messages.
Here is my controller
#Component
#Controller
public class DiscussionController {
#MessageMapping("/discussion")
public void post(DiscussionMessage message) {
}
}
Here is my config file
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
private final Logger log = LoggerFactory.getLogger(WebSocketConfig.class);
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("topic");
config.setApplicationDestinationPrefixes("ngdesk");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ngdesk-websocket").setAllowedOrigins("*").withSockJS();
}
}
You need to configure the web-socket transport, e.g.:
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setMessageSizeLimit(512 * 1024); // 512K
}

ConvertAndSendToUser SpringStomp Sockjs not working SimpMessagingTemplate

I want to send notification to specific user. My client side code is:
stompClient.connect({},function (frame) {
stompClient.subscribe('user/queue/notification', function(response){
alert(angular.fromJson(response.body));
});
Here's my server configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/myWebSocketEndPoint")
.setAllowedOrigins("*")
.withSockJS();
}
}
Here's my server message-sender:
#Component
public class MenuItemNotificationSender {
public void sendNotification(MenuItemDto menuItem, String username) {
String address = "/queue/notification";
System.out.println(username);
messagingTemplate.convertAndSendToUser(username,address, menuItem);
}
}
The messages are sent correctly, to the correct username, but why client doesn't receive them?

Spring Websocket - How can I detect client disconnect

I am new to spring
I have this class :
public class Server extends TextWebSocketHandler implements WebSocketHandler {
WebSocketSession clientsession;
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
clientsession = session;
}
I need to detect a client disconnect on clientsession.
implement ApplicationListener but its not clear how I can register the listener?
do I need to do it in my web.xml ?
The WebSocketHandler afterConnectionClosed function is called after a websocket client disconnects. You simply need to override this in the manner that you override handleTextMessage.
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus){
// your code here
}
There may be substantial delay between the client disconnect and your server event detection. See details about real-time disconnection detection.
You will need to override configureClientOutboundChannel and configureClientInboundChannel of AbstractWebSocketMessageBrokerConfigurer, providing your interceptor
Another way is using ApplicationEvents.
Both methods are described here:
http://www.sergialmar.com/2014/03/detect-websocket-connects-and-disconnects-in-spring-4/
public class StompConnectEvent implements ApplicationListener<SessionConnectEvent> {
private final Log logger = LogFactory.getLog(StompConnectEvent.class);
public void onApplicationEvent(SessionConnectEvent event) {
StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
String company = sha.getNativeHeader("company").get(0);
logger.debug("Connect event [sessionId: " + sha.getSessionId() +"; company: "+ company + " ]");
}
}
I hope that help. Let me know if I need to explain more.
You can use listeners to detect when session is connected or closed.
More information about listeners you can find by this link.
Example how to detect connected session:
#Component
public class SessionConnectedEventListener implements ApplicationListener<SessionConnectedEvent> {
private IWebSocketSessionService webSocketSessionService;
public SessionConnectedEventListener(IWebSocketSessionService webSocketSessionService) {
this.webSocketSessionService = webSocketSessionService;
}
#Override
public void onApplicationEvent(SessionConnectedEvent event) {
webSocketSessionService.saveSession(event);
}
}
Example how to detect when session is disconneted:
#Component
public class SessionDisconnectEventListener implements ApplicationListener<SessionDisconnectEvent> {
private IWebSocketSessionService webSocketSessionService;
public SessionDisconnectEventListener(IWebSocketSessionService webSocketSessionService) {
this.webSocketSessionService = webSocketSessionService;
}
#Override
public void onApplicationEvent(SessionDisconnectEvent event) {
webSocketSessionService.removeSession(event);
}
}
What you probably want to achieve is maintaining multiple sessions. Something like this:
public class Server extends TextWebSocketHandler implements WebSocketHandler {
private List<WebSocketSession> sessions = new ArrayList<>();
#Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session);
}
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// clientsession = session;
// Send individual or broadcast messages here ...
session.sendMessage(new TextMessage(textMessage + "!"));
}
}

Resources