I am connection through SockJS over STOMP to my Spring backend. Everything work fine, the configuration works well for all browsers etc. However, I cannot find a way to send an initial message. The scenario would be as follows:
function connect() { var socket = new SockJS('http://localhost:8080/myEndpoint'); stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { setConnected(true); console.log('Connected: ' + frame); stompClient.subscribe('/topic/notify', function(message){ showMessage(JSON.parse(message.body).content); }); }); }
and the backend config looks more or less like this:
@Configuration @EnableWebSocketMessageBroker public class WebSocketAppConfig extends AbstractWebSocketMessageBrokerConfigurer { ... @Override public void registerStompEndpoints(final StompEndpointRegistry registry) { registry.addEndpoint("/myEndpoint").withSockJS(); }
Usually I do it the following way, e.g. in a REST controller, when the template is already autowired:
@Autowired private SimpMessagingTemplate template; ... template.convertAndSend(TOPIC, new Message("it works!"));
How to achieve this on connect event?
UPDATE
I have managed to make it work. However, I am still a bit confused with the configuration. I will show here 2 configurations how the initial message can be sent:
1) First solution
JS part
stompClient.subscribe('/app/pending', function(message){
showMessage(JSON.parse(message.body).content);
});
stompClient.subscribe('/topic/incoming', function(message){
showMessage(JSON.parse(message.body).content);
});
Java part
@Controller
public class WebSocketBusController {
@SubscribeMapping("/pending")
Configuration
@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
... and other calls
template.convertAndSend("/topic/incoming", outgoingMessage);
2) Second solution
JS part
stompClient.subscribe('/topic/incoming', function(message){
showMessage(JSON.parse(message.body).content);
})
Java part
@Controller
public class WebSocketBusController {
@SubscribeMapping("/topic/incoming")
Configuration
@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
// NO APPLICATION PREFIX HERE
}
... and other calls
template.convertAndSend("/topic/incoming", outgoingMessage);
SUMMARY:
The first case uses two subscriptions - this I wanted to avoid and thought this can be managed with one only.
The second one however has no prefix for application. But at least I can have a single subscription to listen on the provided topic as well as send initial message.
If you just want to send a message to the client upon connection, use an appropriate ApplicationListener:
@Component
public class StompConnectedEvent implements ApplicationListener<SessionConnectedEvent> {
private static final Logger log = Logger.getLogger(StompConnectedEvent.class);
@Autowired
private Controller controller;
@Override
public void onApplicationEvent(SessionConnectedEvent event) {
log.debug("Client connected.");
// you can use a controller to send your msg here
}
}
You can't do that on connect
, however the @SubscribeMapping
does the stuff in that case.
You just need to mark the service method with that annotation and it returns a result to the subscribe
function.
From Spring Reference Manual:
An @SubscribeMapping annotation can also be used to map subscription requests to @Controller methods. It is supported on the method level, but can also be combined with a type level @MessageMapping annotation that expresses shared mappings across all message handling methods within the same controller.
By default the return value from an @SubscribeMapping method is sent as a message directly back to the connected client and does not pass through the broker. This is useful for implementing request-reply message interactions; for example, to fetch application data when the application UI is being initialized. Or alternatively an @SubscribeMapping method can be annotated with @SendTo in which case the resulting message is sent to the "brokerChannel" using the specified target destination.
UPDATE
Referring to this example: https://github.com/revelfire/spring4Test how would that be possible to send anything when the line 24 of the index.html is invoked: stompClient.subscribe('/user/queue/socket/responses' ... from the spring controllers?
Well, look like this:
@SubscribeMapping("/queue/socket/responses")
public List<Employee> list() {
return getEmployees();
}
The Stomp client part remains the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With