How to send message to WebSocket client from Spring WebSocket server using STOMP? - spring

I have two Spring Boot WebSocket applications using STOMP:
WebSocket server
WebSocket client
I am able to send a WebSocket message from the client and respond to it from the server. However, now I would like to send a WebSocket message to the client triggered by an event on the server side.
Can someone tell me a way to do this?
Here is what I have now on the server side:
WebSocketConfig.java:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic/");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/alarm");
}
}
WebSocketController.java:
#Controller
public class WebSocketController {
#MessageMapping("/alarm")
#SendTo("/topic/message")
public void processMessageFromClient(#Payload String message, Principal principal) throws Exception {
System.out.println("WEBSOCKET MESSAGE RECEIVED" + message);
}
#RequestMapping(value = "/start/{alarmName}", method = RequestMethod.POST)
public String start(#PathVariable String alarmName) throws Exception {
System.out.println("Starting " + alarmName);
/* SEND MESSAGE TO WEBSOCKET CLIENT HERE */
return "redirect:/";
}
}

I found the answer on the official spring documentation.
You just need to inject a SimpMessagingTemplate.
My controller now looks like this:
#Controller
public class WebSocketController {
private SimpMessagingTemplate template;
#Autowired
public WebSocketController(SimpMessagingTemplate template) {
this.template = template;
}
#MessageMapping("/alarm")
#SendTo("/topic/message")
public void processMessageFromClient(#Payload String message, Principal principal) throws Exception {
System.out.println("WEBSOCKET MESSAGE RECEIVED" + message);
}
#RequestMapping(value = "/start/{alarmName}", method = RequestMethod.POST)
public String start(#PathVariable String alarmName) throws Exception {
System.out.println("Starting " + alarmName);
this.template.convertAndSend("/topic/message", alarmName);
return "redirect:/";
}
}

Related

Springboot websocket give 404 error in postman

I am writing a chatroom service by springboot websocket.And i want to build multiple chatrooms for the clients base on the url.But it fail when testing postman with 404 not found
My controller :
#Controller
public class ChatroomController {
private final ChatroomService chatroomService;
private final SimpMessageSendingOperations messagingTemplate;
public ChatroomController(ChatroomService chatroomService, SimpMessageSendingOperations messagingTemplate) {
this.chatroomService = chatroomService;
this.messagingTemplate = messagingTemplate;
}
//send chat
#MessageMapping("/chat/{roomId}/sendMessage")
public ChatMessage sendMessage(#DestinationVariable String roomId, #Payload ChatMessage chatMessage) {
return chatroomService.sendMessage(roomId,chatMessage);
}
My service:
#Service
#Slf4j
public class ChatroomService {
private final ChatroomRepository chatroomRepository;
private final SimpMessageSendingOperations messagingTemplate;
public ChatroomService(ChatroomRepository chatroomRepository, SimpMessageSendingOperations messagingTemplate) {
this.chatroomRepository = chatroomRepository;
this.messagingTemplate = messagingTemplate;
}
public ChatMessage sendMessage(String roomId, ChatMessage chatMessage) {
//check chatroom is existed
chatMessage.setDateTime(Instant.now());
chatMessage.setOrder_id(roomId);
messagingTemplate.convertAndSend(format("/channel/%s", roomId), chatMessage);
ChatMessage savedchat=chatroomRepository.save(chatMessage);
return savedchat;
}
My config:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
#Override //register the endpoint
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
registry.addEndpoint("/ws");
//sockJs is for setting the STOMP =>send message to who(subscribe)
}
#Override //control with "/app" can access
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/Chatroom");
// '/topic' is access the broker
registry.enableSimpleBroker("/channel");
}
When i test with: ws://localhost:8084/ws/chat/12/sendMessage, it give the 404 error, but when i test with ws://localhost:8084/ws, it connected.Is there any problem on my url?
Error :
Invalid SockJS path '/chat/12' - required to have 3 path segments"
try configuring your application to run on a different port by adding this to your application.properties
server.port = 8081

How to send message using websocket whenever an API is called using springboot?

I have a simple controller which return name . I have websocket handler which return message to client as: Hey there, presentation recieved from user. whenever http://localhost:8080/sample is called, i need to display the above message to <ws://localhost:8080/presentation>, using https://websocketking.com/ to connect to websocket.
#RestController
public class WebController {
#RequestMapping("/sample")
public SampleResponse Sample(#RequestParam(value = "name",
defaultValue = "Robot") String name) {
SampleResponse response = new SampleResponse();
response.setId(1);
response.setMessage("Your name is "+name);
return response;
}
}
#Component
public class WebSocketHandler extends AbstractWebSocketHandler {
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
System.out.println("New Text Message Received from presetation");
String payload = message.getPayload();
System.out.println(payload);
session.sendMessage(new TextMessage("Hey there, presentation recieved from user"));
}
}
public class WebSocketConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new WebSocketHandler(), "/presentation").setAllowedOrigins("*");
}
}

How to pass message to controller by #MessageMapping with specified user url?

I have such problem. When i try to send message from client side to server, it doesn't match with my #MessageMapping methods. I don't know how to intercept messages on controller layer.
Client side
sends message (it's react-stomp that uses sockjs):
move = (move) => {
this.clientRef.sendMessage("/user/${this.state.opponentId}/queue/move", JSON.stringify(move))
};
Server side. WebSocketConfig:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/handler")
.setHandshakeHandler(new CustomHandshakeHandler())
.setAllowedOrigins("http://localhost:3000")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry brokerRegistry) {
brokerRegistry.setApplicationDestinationPrefixes("/app");
brokerRegistry.enableSimpleBroker("/topic", "/queue", "/user");
}
#EventListener
void handleSessionConnectedEvent(SessionConnectedEvent event) {
StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
}
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new MyChannelInterceptor());
}
}
I also added interceptor class to check path of incomming message:
public class MyChannelInterceptor implements ChannelInterceptor {
#Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
return message;
}
}
On debugging of MyChannelInterceptor i see message with payload and headers. There is simpDestination header with such value:
/user/baedde36-0f9e-4fa5-b8d7-687db1dbcd67/queue/move
What #MessageMapping value should i write to handle messages from specified users? This message succesfully gets to frontside by subscription on this topic but doesn't stay on any controller:
`/user/${message}/queue/move`
I just want to handle messages on server side but i can't catch it there.
Okay. As i understood there is 3 ways to handle websocket messages:
/app - handles with controller
/user - handles with broker, sends messages to specific users
/topic - broadcast to topic for all subscribers
In my situation i just need to create json object with userId, receiverId and message. On server side add DTO class and get it as attribute in my controller method.
Solution:
move = (move) => {
let moveDto = {move: move, userId: this.state.userId, opponentId: this.state.opponentId}
this.clientRef.sendMessage(`/app/move`, JSON.stringify(moveDto))
};
Server side:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class MoveDto {
private String userId;
private String opponentId;
private int move;
}
Controller class:
#RestController
public class GameController {
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
...//some code here
#MessageMapping("/move")
public void message(MoveDto moveDto) {
String userMessage= "foo";
String opponentMessage = "bar";
simpMessagingTemplate.convertAndSendToUser(
moveDto.getUserId(), "/queue/message", userMessage);
simpMessagingTemplate.convertAndSendToUser(
moveDto.getOpponentId(), "/queue/message", opponentMessage );
}

What does this websocket api means?

I have created spring boot websocket project. I want to know what does
localhost:9090/gs-guide-websocket/parm1/param2/websocket
This Api means?
here i know 'gs-guide-websocket' is my websocket end point but what is the rest of all?
WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
Controller.java
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
}
In the about Url what is the sender identity and whom we are sending?
Code is working fine.
The #MessageMapping annotation ensures that if a message is sent to destination "/hello", then the greeting() method is called.
After the 1 second delay, the greeting() method creates a Greeting object and returns it. The return value is broadcast to all subscribers to "/topic/greetings" as specified in the #SendTo annotation.
Refer This Example

Getting Spring simpMessagingTemplate to work with websocket

I have been trying to get simpMessagingTemplate to send to websocket in Spring but to no avail. From what I can see of related stackoverflow posts and other guides, I have provided the necessary configuration and mapping of paths.
My code is shown as below:
RestController (which I use to invoke sending of the message to the websocket):
#RestController
public class RestControllers {
#Autowired
private SimpMessagingTemplate template;
#RequestMapping("/test")
public String doTest() {
Message m = new Message();
m.setFrom("foo");
m.setText("bar");
template.convertAndSend("/app/chat/test-topic", m);
return m.toString();
}
}
Controller:
#Controller
public class ChatController
{
#MessageMapping("/chat/{topic}")
#SendTo("/topic/messages")
public OutputMessage send(#DestinationVariable("topic") String topic,
Message message) throws Exception
{
System.out.println("THE MESSAGE WAS RECEIVED:" + message.toString());
return new OutputMessage(message.getFrom(), message.getText(), topic);
}
}
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) //?? alternative only?
{
registry.addEndpoint("/chat").setAllowedOrigins("*").withSockJS();
}
}

Resources