WebSocket with Spring Boot
WebSocket enables real-time, bidirectional communication — chat, live notifications, real-time dashboards.
Setup
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocket Configuration
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue"); // server → client
config.setApplicationDestinationPrefixes("/app"); // client → server
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("http://localhost:3000")
.withSockJS(); // fallback for old browsers
}
}
Message Controller
@Controller
public class ChatController {
@MessageMapping("/chat.send") // client sends to /app/chat.send
@SendTo("/topic/messages") // broadcast to all subscribers
public ChatMessage sendMessage(ChatMessage message) {
return message;
}
@MessageMapping("/chat.join")
@SendTo("/topic/messages")
public ChatMessage addUser(ChatMessage message, SimpMessageHeaderAccessor headerAccessor) {
headerAccessor.getSessionAttributes().put("username", message.getSender());
message.setType(MessageType.JOIN);
return message;
}
}
public class ChatMessage {
private MessageType type; // CHAT, JOIN, LEAVE
private String content;
private String sender;
private LocalDateTime timestamp;
// getters, setters
}
public enum MessageType { CHAT, JOIN, LEAVE }
Sending Messages from Services
@Service
public class NotificationService {
private final SimpMessagingTemplate messagingTemplate;
public NotificationService(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
// Broadcast to all subscribers of /topic/notifications
public void broadcastNotification(String message) {
messagingTemplate.convertAndSend("/topic/notifications",
new Notification(message, LocalDateTime.now()));
}
// Send to a specific user
public void sendToUser(String username, String message) {
messagingTemplate.convertAndSendToUser(
username, "/queue/private",
new Notification(message, LocalDateTime.now()));
}
}
JavaScript Client
const socket = new SockJS('/ws');
const stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
// Subscribe to broadcast messages
stompClient.subscribe('/topic/messages', function(message) {
const chatMessage = JSON.parse(message.body);
displayMessage(chatMessage);
});
// Subscribe to private messages
stompClient.subscribe('/user/queue/private', function(message) {
displayPrivateMessage(JSON.parse(message.body));
});
// Send a message
stompClient.send('/app/chat.send', {},
JSON.stringify({ sender: 'Alice', content: 'Hello!', type: 'CHAT' }));
});
Connection Events
@Component
public class WebSocketEventListener {
@EventListener
public void handleConnect(SessionConnectedEvent event) {
log.info("New WebSocket connection");
}
@EventListener
public void handleDisconnect(SessionDisconnectEvent event) {
StompHeaderAccessor headers = StompHeaderAccessor.wrap(event.getMessage());
String username = (String) headers.getSessionAttributes().get("username");
if (username != null) {
log.info("User disconnected: {}", username);
messagingTemplate.convertAndSend("/topic/messages",
new ChatMessage(MessageType.LEAVE, null, username, LocalDateTime.now()));
}
}
}
Key Takeaways
- WebSocket = persistent, bidirectional connection (unlike HTTP request-response).
- STOMP protocol provides subscribe/publish messaging over WebSocket.
/topic/for broadcasts,/queue/for point-to-point,/user/for user-specific.SimpMessagingTemplatesends messages from any service.- SockJS provides fallback for browsers without WebSocket support.
What’s Next?
Next: GraphQL with Spring Boot — query exactly what you need.