I am using Spring Websocket with STOMP, Simple Message Broker.
In my @Controller
I use method-level @SubscribeMapping
, which should subscribe the client to a topic so that the client would receive the messages of that topic afterwards. Let say, the client subscribes to the topic "chat":
stompClient.subscribe('/app/chat', ...);
As the client subscribed to "/app/chat", instead of "/topic/chat", this subscription would go to the method which is mapped using @SubscribeMapping
:
@SubscribeMapping("/chat")
public List getChatInit() {
return Chat.getUsers();
}
Here is what Spring ref. says:
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.
Okay, this was what I would want, but just partially!! Sending some init-data after subscribing, well. But what about subscribing? It seems to me that the thing what happened here is just a request-reply, like a service. The subscription is just consumed. Please clarify me if this is the case.
- Did the client subscribe to some where, if the broker is not involved in this?
- If later I want to send some message to "chat" subscriptors, would the client receive it? It doesnt seem so.
- Who realizes subscriptions really? Broker? Or some one else?
If here the client is not being subscribed to any where, I wonder why we call this as "subscribe"; because the client receives just one message and not future messages.
EDIT:
To make sure that the subscription has been realized, what I tried is as following:
SERVER-side:
Configuration:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").withSockJS();
}
}
Controller:
@Controller
public class GreetingController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
System.out.println("inside greeting");
return new Greeting("Hello, " + message.getName() + "!");
}
@SubscribeMapping("/topic/greetings")
public Greeting try1() {
System.out.println("inside TRY 1");
return new Greeting("Hello, " + "TRY 1" + "!");
}
}
CLIENT-side:
...
stompClient.subscribe('/topic/greetings', function(greeting){
console.log('RECEIVED !!!');
});
stompClient.send("/app/hello", {}, JSON.stringify({ 'name': name }));
...
What I would like to happen:
- When client subscribes to '
/topic/greetings
', the methodtry1
is executed. - When the client sends msg to '
/app/hello
', it should receive the greetings msg which would be@SendTo
'/topic/greetings
'.
Results:
If the client subscribes to
/topic/greetings
, the methodtry1
is UNABLE to catch it.When the client sends msg to '
/app/hello
',greeting
method was executed, and the client received the greetings message. So we understood that it had been subscribed to '/topic/greetings
' correctly.But remember 1. was failed. After some try, it has been possible when the client subscribed to
'/app/topic/greetings'
, i.e. prefixed with/app
(This is understandable by configuration).Now 1. is working, however this time 2. is failed: When the client sends msg to '
/app/hello
', yes,greeting
method was executed, but the client did NOT receive the greetings message. (Because probably now the client was subscribed to the topic prefixed with '/app
', which was unwanted.)
So, what I got is either 1 or 2 of what I would like, but not these 2 together.
- How do I achieve this with this structure (configuring mapping paths correctly) ?