Getting Spring simpMessagingTemplate to work with websocket - spring-boot

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();
}
}

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 can i notify subscriber of the API when that API is called?

I have a Rest API like this:
#RestController
#RequestMapping(path="/employee")
public class EmployeeController {
private final EmpleyeeService employeeService;
public EmployeeController(EmpleyeeService textService) {
this.employeeService = employeeService;
}
#RequestMapping(method = RequestMethod.POST , value = "/add-emplyee")
public void addEmployee(){
//TODO: receive emplyee from input
employeeService.save(emplyee);
}
}
I want when addEmployee Rest AOI is called then the clients who subscribe to this API get notified. So I created WebsocketConfig like this:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry){
registry.addEndpoint("/socket").setAllowedOrigins("*").withSockJS();
}
}
Is that correct? What else should I do?
I've done something like that with this method(line 27)
check the full source here https://github.com/fajaralmu/base_web_app/blob/master/src/main/java/com/fajar/entitymanagement/service/RealtimeService2.java

Injecting dependency inside AbstractWebSocketHandler

How to inject a dependency inside a Web Socket handler:
public class WebsocketHandler extends AbstractWebSocketHandler {
#Autowired
GreetingMap greetingMap;
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
// NullPointerException here
String greeting = greetingMap.getSampleGreetings().get("hello") + " " + message.getPayload();
session.sendMessage(new TextMessage(greeting));
}
}
The code above throws NullPointerException
What could be missing here?
Try using dependency injection with constructor instead #Autowired:
private GreetingMap greetingMap;
public WebsocketHandler(GreetingMap greetingMap){
this.greetingMap = greetingMap
}
I think the problem is that SocketHanler is not a spring bean, but is created by "new" operator:
#Configuration
#EnableWebSocket
public class WebSocketsConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(), "/socket")
.setAllowedOrigins("*");
}
}
What you need to do in this case, is to inject your dependency into WebSocketConfiguration and pass it manually to SocketHandler constructor:
#Configuration
#EnableWebSocket
public class WebSocketsConfiguration implements WebSocketConfigurer {
#Autowired
MyDependency myDependency;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(myDependency), "/socket")
.setAllowedOrigins("*");
}
}
And in the handler, you need to add constructor that receives the dependency
public class SocketHandler extends AbstractWebSocketHandler {
private MyDependency myDependency;
public SocketHandler(MyDependency myDependency) {
this.myDependency = myDependency;
}
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
System.out.println(String.format("Message from client: %s", message));
}
}

Large messages failing on Stomp Controller in Spring Boot

I have a stomp controller in a spring boot application, When ever i send a message which exceeds 256kb it fails to enter the controller. I don't see any error messages. Is there any setting where I can configure it to allow larger messages.
Here is my controller
#Component
#Controller
public class DiscussionController {
#MessageMapping("/discussion")
public void post(DiscussionMessage message) {
}
}
Here is my config file
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
private final Logger log = LoggerFactory.getLogger(WebSocketConfig.class);
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("topic");
config.setApplicationDestinationPrefixes("ngdesk");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ngdesk-websocket").setAllowedOrigins("*").withSockJS();
}
}
You need to configure the web-socket transport, e.g.:
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setMessageSizeLimit(512 * 1024); // 512K
}

ConvertAndSendToUser SpringStomp Sockjs not working SimpMessagingTemplate

I want to send notification to specific user. My client side code is:
stompClient.connect({},function (frame) {
stompClient.subscribe('user/queue/notification', function(response){
alert(angular.fromJson(response.body));
});
Here's my server configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/myWebSocketEndPoint")
.setAllowedOrigins("*")
.withSockJS();
}
}
Here's my server message-sender:
#Component
public class MenuItemNotificationSender {
public void sendNotification(MenuItemDto menuItem, String username) {
String address = "/queue/notification";
System.out.println(username);
messagingTemplate.convertAndSendToUser(username,address, menuItem);
}
}
The messages are sent correctly, to the correct username, but why client doesn't receive them?

Resources