Spring WebSocket: broadcasting messages to users - java

I am implementing a simple Spring Boot application which has a certain number of users connected via the WebSocket protocol. The application sends personal statistics to each user every 5 seconds.
I am using the #SendToUser annotation to distinguish between users and personalize the statistics.
It seems to me that the method, annotated with #SendToUser, can be only used as a message-handling method. This means that in order to receive the statistics the user should first send the message to the Spring Boot application, then the message-handling method will be called, and only then the statistics will be sent back.
As a result, the WebSocket protocol does now look very useful: the request is still initiated by a user (by the user's browser, to be precise). The only advantage is that you should not open new connection every time you want to retrieve the fresh statistics.
Is it possible to get rid of the messages sent from the users to the application at all? For example, to retrieve the list of the currently connected users every 5 seconds, then iterate over the list and send the message to every user one by one? Or a user still needs to initiate the statistics retrieval?

You can inject SimpMessagingTemplate to any spring bean and send message to an user.
simpMessagingTemplate.convertAndSendToUser(username, "/destination", message);
See https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/simp/SimpMessagingTemplate.html
You can retrieve list of the connected users by injecting SimpUserRegistry bean.
See https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/simp/user/SimpUserRegistry.html

Related

Reading messages from Azure Service Bus queue with specific correlation id

Is there any way of only receive messages from an Azure Service Bus queue with a specific correlation id?
The scenario is:
I am receiving a REST API call to my application A
My application A will generate an unique correlation id
My application A will send a request to another application B and include the correlation id. This request is not sent on the Azure Service Bus - with via another mechanism.
The application B will perform some logic and send a reply message on an Azure Service Bus queue with the correlation id it received in (3)
My application A wants to read only the message from the queue with the corresponding correlation id and generate a response to the initial caller based on this reply message.
I see that there is a concept of sessions, but it seems a bit overkill to create new sessions for each request to my application. I cannot reuse correlation id, because I need them to be unique for each request to my application. I see that an alternative could be to use a topic and subscribe with a filter, but that also seems like overkill.
Any ideas?

Best way to use Websocket with Spring Boot and Vuejs

I try to use Websocket with spring boot backend (as an API) and Vuejs frontend.
I take a simple use case to expose my question. Some users are logged on my website, and there is a messaging feature. User A send a message to User B. User B is actually logged, and I want to notify User B that a new message is arrived.
I see 3 ways to do it with websockets :
1 - When User A send message, an Axios post is call to the API for saving message, and, if the Axios response is success, I call something like
this.stompClient.send("/app/foo", JSON.stringify(bar), {})
2 - When User A send message, I only call something like
this.stompClient.send("/app/foo", JSON.stringify(bar), {})
and it's my controller's method (annotated with #MessageMapping("/xxxx") #SendTo("/topic/yyyy")) that call facade, service, dao to first, save message, then return message to subscribers
3 - I keep my actuals controllers, facade, services and DAO, and juste add when save is successfull something like :
#Autowired SimpMessagingTemplate webSocket;
...
#GetMapping("/send-message")
public ResponseEntity sendMessage(#AuthenticationPrincipal User user, ....) {
service.saveMessage(....);
webSocket.convertAndSend("/ws/message-from", message);
without a new controller contains #MessageMapping("/xxxx") #SendTo("/topic/yyyy"). User B is just subscibed to "/ws/message-from"
Could you help me.
In the 3 way there is a good method ?
Thanks you.
The one and two method has no much difference as you use axios from npm for sending request and the other one you can directly,while the third one you use controller,and facade dao at single place.it is about architecture and how you wanna send your requests for your framework,as a requirement.
They serve best at their level,till you come with specific requirement.
The suggestion would be to use axios.
It has advantages:
supports older browsers (Fetch needs a polyfill)
has a way to abort a request
has a way to set a response timeout
has built-in CSRF protection
supports upload progress
performs automatic JSON data transformation
works in Node.js

Spring as Broker Relay by using an external Message Broker

I would like to use Spring Messaging to create a real time notification system for logged users for my webapp.
I defined a AbstractWebSocketMessageBrokerConfigurer as follows:
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/notifications").withSockJS()
.setSessionCookieNeeded(true)
.setWebSocketEnabled(true);
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic/", "/queue/");
}
And, according to the documentation:
An application can send messages targeting a specific user. Spring’s STOMP support recognizes destinations prefixed with "/user/". For example, a client might subscribe to the destination "/user/queue/position-updates". This destination will be handled by the UserDestinationMessageHandler and transformed into a destination unique to the user session, e.g. "/queue/position-updates-user123". This provides the convenience of subscribing to a generically named destination while at the same time ensuring no collisions with other users subscribing to the same destination so that each user can receive unique stock position updates.
On the sending side messages can be sent to a destination such as "/user/{username}/queue/position-updates", which in turn will be translated by the UserDestinationMessageHandler into one or more destinations, one for each session associated with the user. This allows any component within the application to send messages targeting a specific user without necessarily knowing anything more than their name and the generic destination. This is also supported through an annotation as well as a messaging template.
By sending a message to /user/{username}/queue/something, it will be delivered only to the specific user identified by {username}.
Now, I'm looking for a solution that allows me to use an external Message Broker (for instance, RabbitMQ), with Spring just as Broker Relay:
registry.enableStompBrokerRelay("/topic/", "/queue/");
After configuring the External Message Broker in Spring:
Is it possible to send a message on Message Broker by using as channel /user/{username/}/queue/something? If yes, how?
By sending a message on Message Broker by using as channel /user/{username/}/queue/something, is Spring able to send that message only to {username} according to the current Principal?
Yes it is possible, if you enable an external broker, every #MessageMapping return value will be serialized to JSON and sent to the broker, have a look to the Flow of Messages section of the reference documentation for more details. So it is basically the same that with the simple broker.
You can also inject a SimpMessagingTemplate or SimpMessageSendingOperations bean, like it is done in my OpenSnap example application. You can use this from a Controller, but also from any other class in a pure push context.
You can retrieve the principal by adding a Principal parameter to your #MessageMapping or #SubscribeMapping handler method, like it is done here, the current principal will be automatically injected.

RPC over STOMP using Spring, and correctly handling server side errors propagated to clients

I need to implement RPC over STOMP, where the client runs with javascript in a browser, and the server side is implemented using Spring messaging capabilities.
While using #MessageMapping is fine for normal messaging, I find using #SendToUser quite limitating for implementing RPC because the client has an hard time to understand which reply is associated with which request in a scenario when multiple simultaneous requests are being made from the client.
Of course there is no problem when just only one request is made, and the client waits for its reply, but problems arise when the client has to keep track of multiple "open" rpc calls.
I've managed to make the system mostly fine by associating an ID with every request, i.e.: the client sends an id together with the message, and the server replies with a special message wrapper that contains this id, so the client is able to associate asynchronous replies with requests.
This works fine but has several limitations:
I have to develop code that needs to understand this structure, and that defies the uitlity to have simple annotated methods
when the server side code generates an Exception the Spring #MessageExceptionHandler get called and the correct Exception is returned to the client, but the request id is lost because the handler has no (easy) way to access it.
I know that with rabbitmq we can add "reply-to" header to every request that needs to be associated with a special reply (the rpc response), and this is implemented by creating a special temporary queue that the user is automatically subscribed to, but how may I use this scheme in Spring? Also, that would tie me a specific broker.
How may I elegantly implement a correct RPC call in Spring that correctly handles server side exceptions?
I find this a general problem and I think Spring could benefit greatly to implement it natively.
This not exactly what you demand, but maybe you can attempt something like this :
Path variables in Spring WebSockets #SendTo mapping
You define an ID on your client and send id to the queue /user/queue/{myid}
On the serveur side you will have a class who looks like this :
#MessageMapping("/user/queue/{myid}")
public void simple(#DestinationVariable String id, Object requestDto) {
simpMessagingTemplate.convertAndSendToUser(userId, "/user/queue/" + id, responseDto);
}
This solution can work with the same principle as the rabbit mq solution you mention.
Hope this helps.
If you do not need the exception/reason on the client, but only want to know which message failed you could send ack messages for successful messages. For successful messages you always have easy access to the message id / headers. By the absence of the ack message the client knows which message has failed.
Of course this comes at the costs of sending all the ack messages and knowing the timout of requests. Also additional code is required to keep track on the client side, but this can be done using a middleware and would end up in an ok-ish dev experience for the business logic.

callback function do background jobs after the completing the action in java spring

I am new to Java Spring Framework, I am Rails developer I have requirement in java spring like I need to do background jobs but after the response send to the end User. It should not wait for the jobs to complete. But the jobs should run every time action completes.
Is a webservice app. We have Service, Bo and DAO layers and we are logging any exceptions occurred while processing the user data in database before response send to user, but now we want to move(Exception handling) after response send to user to increase the performance.
I remember in rails we have callbacks/filters after the action executed it calls the methods we want to executed. Same is available in java Spring?
Thanks,
Senthil
I assume the use case is something like a user requests a long-running task, and you want to return a response immediately and then launch the task in the background.
Spring can help with this. See
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/scheduling.html
In particular see the #Async annotation.
With respect to the client getting a response back following the async processing (exception or otherwise), you can do it, but it's extra work.
Normally the immediate response would include some kind of ID that the client could come back with after some period of time. (For example, when you run a search against the Splunk API, it gives you a job ID, and you come back later with that job ID to check on the result). If this works, do that. The client has to poll but the implementation is the simplest.
If not, then you have to have some way for the client to listen for the response. This could be a "reply-to" web service endpoint on the client (perhaps passed in with the original request as a custom X-Reply-To HTTP header), or it could be a message queue, etc.

Categories

Resources