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 :
Sent Message :
Connected to WebSocket for Recipient:
URL: ws://localhost:8080/ws/10002
Sent STOMP Connect message:
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:
Handshake Interceptor:
WebSocket Handler:
CONNECT
accept-version:1.2
heart-beat:10000,10000
\0
CONNECT
accept-version:1.2
heart-beat:10000,10000
\0
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
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
@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();
}
}
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);
}
}
@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);
}
}
1 Reply
@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);
}
}
@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);
}
}