Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Path variables in Spring WebSockets @SendTo mapping

I have, what I think to be, a very simple Spring WebSocket application. However, I'm trying to use path variables for the subscription as well as the message mapping.

I've posted a paraphrased example below. I would expect the @SendTo annotation to return back to the subscribers based on their fleetId. ie, a POST to /fleet/MyFleet/driver/MyDriver should notify subscribers of /fleet/MyFleet, but I'm not seeing this behavior.

It's worth noting that subscribing to literal /fleet/{fleetId} works. Is this intended? Am I missing some piece of configuration? Or is this just not how it works?

I'm not very familiar with WebSockets or this Spring project yet, so thanks in advance.

Controller.java

... @MessageMapping("/fleet/{fleetId}/driver/{driverId}") @SendTo("/topic/fleet/{fleetId}") public Simple simple(@DestinationVariable String fleetId, @DestinationVariable String driverId) {     return new Simple(fleetId, driverId); } ... 

WebSocketConfig.java

@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {     @Override     public void configureMessageBroker(MessageBrokerRegistry config) {         config.enableSimpleBroker("/topic");         config.setApplicationDestinationPrefixes("/live");     }      @Override     public void registerStompEndpoints(StompEndpointRegistry registry) {         registry.addEndpoint("/fleet").withSockJS();     } } 

index.html

var socket = new SockJS('/fleet'); var stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) {     // Doesn't Work     stompClient.subscribe('/topic/fleet/MyFleet', function(greeting) {     // Works     stompClient.subscribe('/topic/fleet/{fleetId}', function(greeting) {         // Do some stuff     }); }); 

Send Sample

    stompClient.send("/live/fleet/MyFleet/driver/MyDriver", {}, JSON.stringify({         // Some simple content     })); 
like image 572
bvulaj Avatar asked Nov 20 '14 18:11

bvulaj


People also ask

How do you use WebSockets in Spring?

In order to tell Spring to forward client requests to the endpoint , we need to register the handler. Start the application- Go to http://localhost:8080 Click on start new chat it opens the WebSocket connection. Type text in the textbox and click send. On clicking end chat, the WebSocket connection will be closed.

What is registerStompEndpoints?

The registerStompEndpoints() method registers the /gs-guide-websocket endpoint, enabling SockJS fallback options so that alternate transports can be used if WebSocket is not available.

What is setApplicationDestinationPrefixes?

setApplicationDestinationPrefixes("/app") - used to. Configure one or more prefixes to filter destinations targeting application annotated methods. When messages are processed, the matching prefix is removed from the destination in order to form the lookup path.

Does Spring boot support WebSocket?

The Spring Framework provides support for using STOMP — a simple, messaging protocol originally created for use in scripting languages with frames inspired by HTTP. STOMP is widely supported and well suited for use over WebSocket and over the web.


1 Answers

Even though @MessageMapping supports placeholders, they are not exposed / resolved in @SendTo destinations. Currently, there's no way to define dynamic destinations with the @SendTo annotation (see issue SPR-12170). You could use the SimpMessagingTemplate for the time being (that's how it works internally anyway). Here's how you would do it:

@MessageMapping("/fleet/{fleetId}/driver/{driverId}") public void simple(@DestinationVariable String fleetId, @DestinationVariable String driverId) {     simpMessagingTemplate.convertAndSend("/topic/fleet/" + fleetId, new Simple(fleetId, driverId)); } 

In your code, the destination '/topic/fleet/{fleetId}' is treated as a literal, that's the reason why subscribing to it works, just because you are sending to the exact same destination.

If you just want to send some initial user specific data, you could return it directly in the subscription:

@SubscribeMapping("/fleet/{fleetId}/driver/{driverId}") public Simple simple(@DestinationVariable String fleetId, @DestinationVariable String driverId) {     return new Simple(fleetId, driverId); } 

Update: In Spring 4.2, destination variable placeholders are supported it's now possible to do something like:

@MessageMapping("/fleet/{fleetId}/driver/{driverId}") @SendTo("/topic/fleet/{fleetId}") public Simple simple(@DestinationVariable String fleetId, @DestinationVariable String driverId) {     return new Simple(fleetId, driverId); } 
like image 166
Sergi Almar Avatar answered Sep 22 '22 06:09

Sergi Almar