WebSocket Chat Application in Spring Boot Not Receiving Messages in Postman

Problem Description: I'm working on a WebSocket chat application using Spring Boot. The application uses STOMP over WebSocket for communication. When I test the WebSocket connection in Postman, I can establish the connection and send subscribe messages, but I'm not receiving any messages. Here are the details of my setup: WebSocket Endpoint for Sender: ws://localhost:8080/ws/10000 WebSocket Endpoint for Recipient: ws://localhost:8080/ws/10002 Connected to WebSocket for Sender: URL: ws://localhost:8080/ws/10000 Sent STOMP Connect message :
CONNECT
accept-version:1.2
heart-beat:10000,10000

\0
CONNECT
accept-version:1.2
heart-beat:10000,10000

\0
Sent Message :
SEND
destination:/app/chat.sendMessage
content-type:application/json

{
"senderId": 10000,
"recipientId": 10002,
"content": "Hello, World!",
"isPrivate": true
}\0
SEND
destination:/app/chat.sendMessage
content-type:application/json

{
"senderId": 10000,
"recipientId": 10002,
"content": "Hello, World!",
"isPrivate": true
}\0
Connected to WebSocket for Recipient: URL: ws://localhost:8080/ws/10002 Sent STOMP Connect message:
CONNECT
accept-version:1.2
heart-beat:10000,10000

\0
CONNECT
accept-version:1.2
heart-beat:10000,10000

\0
SUBSCRIBE
id:sub-0
destination:/user/10002/queue/messages

\0
SUBSCRIBE
id:sub-0
destination:/user/10002/queue/messages

\0
Current Status: The recipient WebSocket connection shows the subscription message as sent. However, no messages are being received in the recipient's Postman WebSocket session. Relevant Code: WebSocket Configuration:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue");
config.setApplicationDestinationPrefixes("/app");
config.setUserDestinationPrefix("/user");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws/{matricule}")
.setAllowedOrigins("*")
.withSockJS();
}
}
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue");
config.setApplicationDestinationPrefixes("/app");
config.setUserDestinationPrefix("/user");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws/{matricule}")
.setAllowedOrigins("*")
.withSockJS();
}
}
Handshake Interceptor:
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {

@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
String path = request.getURI().getPath();
Long matricule = Long.parseLong(path.substring(path.lastIndexOf('/') + 1));
attributes.put("matricule", matricule);
return super.beforeHandshake(request, response, wsHandler, attributes);
}
}
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {

@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
String path = request.getURI().getPath();
Long matricule = Long.parseLong(path.substring(path.lastIndexOf('/') + 1));
attributes.put("matricule", matricule);
return super.beforeHandshake(request, response, wsHandler, attributes);
}
}
WebSocket Handler:
@Component
public class TradeWebSocketHandler extends TextWebSocketHandler {

private final Map<Long, WebSocketSession> sessions = new HashMap<>();
private final ObjectMapper objectMapper = new ObjectMapper();

@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Long matricule = (Long) session.getAttributes().get("matricule");
sessions.put(matricule, session);
System.out.println("Connected: " + matricule);
}

@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
System.out.println("Received: " + payload);

// Parse the message
ChatMessageDTO chatMessageDTO = objectMapper.readValue(payload, ChatMessageDTO.class);

// Get the recipient's session
WebSocketSession recipientSession = sessions.get(chatMessageDTO.recipientId());
if (recipientSession != null && recipientSession.isOpen()) {
recipientSession.sendMessage(new TextMessage(payload));
}
}

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
Long matricule = (Long) session.getAttributes().get("matricule");
sessions.remove(matricule);
System.out.println("Disconnected: " + matricule);
}
}
@Component
public class TradeWebSocketHandler extends TextWebSocketHandler {

private final Map<Long, WebSocketSession> sessions = new HashMap<>();
private final ObjectMapper objectMapper = new ObjectMapper();

@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Long matricule = (Long) session.getAttributes().get("matricule");
sessions.put(matricule, session);
System.out.println("Connected: " + matricule);
}

@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
System.out.println("Received: " + payload);

// Parse the message
ChatMessageDTO chatMessageDTO = objectMapper.readValue(payload, ChatMessageDTO.class);

// Get the recipient's session
WebSocketSession recipientSession = sessions.get(chatMessageDTO.recipientId());
if (recipientSession != null && recipientSession.isOpen()) {
recipientSession.sendMessage(new TextMessage(payload));
}
}

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
Long matricule = (Long) session.getAttributes().get("matricule");
sessions.remove(matricule);
System.out.println("Disconnected: " + matricule);
}
}
No description
No description
1 Reply
Ninoya
Ninoya4w ago
@Component
public class TradeWebSocketHandler extends TextWebSocketHandler {

private final Map<Long, WebSocketSession> sessions = new HashMap<>();
private final ObjectMapper objectMapper = new ObjectMapper();

@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Long matricule = (Long) session.getAttributes().get("matricule");
sessions.put(matricule, session);
System.out.println("Connected: " + matricule);
}

@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
System.out.println("Received: " + payload);

// Parse the message
ChatMessageDTO chatMessageDTO = objectMapper.readValue(payload, ChatMessageDTO.class);

// Get the recipient's session
WebSocketSession recipientSession = sessions.get(chatMessageDTO.recipientId());
if (recipientSession != null && recipientSession.isOpen()) {
recipientSession.sendMessage(new TextMessage(payload));
}
}

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
Long matricule = (Long) session.getAttributes().get("matricule");
sessions.remove(matricule);
System.out.println("Disconnected: " + matricule);
}
}
@Component
public class TradeWebSocketHandler extends TextWebSocketHandler {

private final Map<Long, WebSocketSession> sessions = new HashMap<>();
private final ObjectMapper objectMapper = new ObjectMapper();

@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Long matricule = (Long) session.getAttributes().get("matricule");
sessions.put(matricule, session);
System.out.println("Connected: " + matricule);
}

@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
System.out.println("Received: " + payload);

// Parse the message
ChatMessageDTO chatMessageDTO = objectMapper.readValue(payload, ChatMessageDTO.class);

// Get the recipient's session
WebSocketSession recipientSession = sessions.get(chatMessageDTO.recipientId());
if (recipientSession != null && recipientSession.isOpen()) {
recipientSession.sendMessage(new TextMessage(payload));
}
}

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
Long matricule = (Long) session.getAttributes().get("matricule");
sessions.remove(matricule);
System.out.println("Disconnected: " + matricule);
}
}
Chat Controller:
@RestController
@RequestMapping("/api/chat")
public class ChatController {

@Autowired
private SimpMessagingTemplate messagingTemplate;

@Autowired
private ChatService chatService;

@MessageMapping("/chat.sendMessage")
public void sendMessage(@DestinationVariable Long matricule, ChatMessageDTO chatMessageDTO) {
ChatMessageDTO updatedChatMessageDTO = new ChatMessageDTO(
null,
chatMessageDTO.senderId(),
chatMessageDTO.recipientId(),
chatMessageDTO.content(),
LocalDateTime.now(),
chatMessageDTO.isPrivate()
);

ChatMessageDTO savedChatMessageDTO = chatService.saveMessage(updatedChatMessageDTO);
System.out.println("Saved ChatMessageDTO: " + savedChatMessageDTO);

try {
messagingTemplate.convertAndSendToUser(
savedChatMessageDTO.recipientId().toString(),
"/queue/messages",
savedChatMessageDTO
);
System.out.println("Message sent to user: " + savedChatMessageDTO.recipientId());
} catch (Exception e) {
System.err.println("Error sending message: " + e.getMessage());
}
}

@GetMapping("/history")
public ResponseEntity<List<ChatMessageDTO>> getChatHistory(@RequestParam Long senderId, @RequestParam Long recipientId) {
List<ChatMessageDTO> messages = chatService.getChatHistory(senderId, recipientId);
return ResponseEntity.ok(messages);
}

@GetMapping("/unique-conversations")
public ResponseEntity<List<Long>> getUniqueConversations(@RequestParam Long userMatricule) {
List<Long> conversations = chatService.getUniqueConversations(userMatricule);
return ResponseEntity.ok(conversations);
}
}
@RestController
@RequestMapping("/api/chat")
public class ChatController {

@Autowired
private SimpMessagingTemplate messagingTemplate;

@Autowired
private ChatService chatService;

@MessageMapping("/chat.sendMessage")
public void sendMessage(@DestinationVariable Long matricule, ChatMessageDTO chatMessageDTO) {
ChatMessageDTO updatedChatMessageDTO = new ChatMessageDTO(
null,
chatMessageDTO.senderId(),
chatMessageDTO.recipientId(),
chatMessageDTO.content(),
LocalDateTime.now(),
chatMessageDTO.isPrivate()
);

ChatMessageDTO savedChatMessageDTO = chatService.saveMessage(updatedChatMessageDTO);
System.out.println("Saved ChatMessageDTO: " + savedChatMessageDTO);

try {
messagingTemplate.convertAndSendToUser(
savedChatMessageDTO.recipientId().toString(),
"/queue/messages",
savedChatMessageDTO
);
System.out.println("Message sent to user: " + savedChatMessageDTO.recipientId());
} catch (Exception e) {
System.err.println("Error sending message: " + e.getMessage());
}
}

@GetMapping("/history")
public ResponseEntity<List<ChatMessageDTO>> getChatHistory(@RequestParam Long senderId, @RequestParam Long recipientId) {
List<ChatMessageDTO> messages = chatService.getChatHistory(senderId, recipientId);
return ResponseEntity.ok(messages);
}

@GetMapping("/unique-conversations")
public ResponseEntity<List<Long>> getUniqueConversations(@RequestParam Long userMatricule) {
List<Long> conversations = chatService.getUniqueConversations(userMatricule);
return ResponseEntity.ok(conversations);
}
}
Why am I not receiving messages in the recipient WebSocket session? Is there a mistake in my WebSocket or STOMP configuration? Are there any specific settings in Postman that I need to adjust for testing WebSocket communication? Is my sendMessage method correctly set up to handle and route messages via STOMP? Any insights or suggestions to resolve this issue would be greatly appreciated. Thank you!