Working with WebSockets
1. Adding WebSocket Dependencies
Example: WebSocket dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. Configuring WebSocket Message Broker
Example: Configure STOMP broker over SockJS
@Configuration
@EnableWebSocketMessageBroker
public class WsConfig implements WebSocketMessageBrokerConfigurer {
@Override public void registerStompEndpoints(StompEndpointRegistry r) {
r.addEndpoint("/ws").setAllowedOriginPatterns("*").withSockJS();
}
@Override public void configureMessageBroker(MessageBrokerRegistry r) {
r.enableSimpleBroker("/topic", "/queue");
r.setApplicationDestinationPrefixes("/app");
r.setUserDestinationPrefix("/user");
}
}
3. Registering STOMP Endpoints
| Method | Use |
|---|---|
addEndpoint("/path") |
STOMP over WebSocket URL |
withSockJS() |
Fallback for older browsers |
setAllowedOriginPatterns(...) |
CORS |
setHandshakeHandler(...) |
Custom user/principal |
4. Configuring Message Broker
| Broker | Use |
|---|---|
| Simple in-memory | Single-node dev/small apps |
| External (RabbitMQ STOMP, ActiveMQ) | Multi-node clustering |
Example: External RabbitMQ STOMP relay
r.enableStompBrokerRelay("/topic","/queue")
.setRelayHost("rabbitmq").setRelayPort(61613)
.setClientLogin("guest").setClientPasscode("guest");
5. Creating Message Handlers (@MessageMapping)
Example: Chat message handler with @MessageMapping
@Controller
public class ChatController {
@MessageMapping("/chat") // client sends to /app/chat
@SendTo("/topic/messages")
public ChatMessage on(ChatMessage in, Principal user) {
return new ChatMessage(user.getName(), in.text(), Instant.now());
}
}
6. Sending Messages to Clients (@SendTo)
| Annotation | Behavior |
|---|---|
@SendTo("/topic/...") |
Broadcast destination |
@SendToUser("/queue/...") |
Per-user queue |
@SubscribeMapping("/init") |
Reply on subscribe |
7. Using SimpMessagingTemplate for Broadcasting
Example: Broadcast and user-specific messaging
@Service
public class Notifier {
private final SimpMessagingTemplate template;
public Notifier(SimpMessagingTemplate template) { this.template = template; }
public void notifyOrder(OrderPlaced o) {
template.convertAndSend("/topic/orders", o);
template.convertAndSendToUser("alice", "/queue/alerts", o);
}
}
8. Handling User-Specific Messages (@SendToUser)
Example: Send reply to user private queue
@MessageMapping("/private")
@SendToUser("/queue/private")
public Reply privateMsg(Message msg, Principal user) {
return new Reply("Hello " + user.getName());
}
9. Implementing WebSocket Interceptors
Example: Authenticate STOMP CONNECT with token
@Override
public void configureClientInboundChannel(ChannelRegistration r) {
r.interceptors(new ChannelInterceptor() {
@Override public Message<?> preSend(Message<?> m, MessageChannel ch) {
StompHeaderAccessor acc = MessageHeaderAccessor.getAccessor(m, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(acc.getCommand())) {
String token = acc.getFirstNativeHeader("Authorization");
// validate; set acc.setUser(...)
}
return m;
}
});
}
10. Handling WebSocket Events
| Event | Description |
|---|---|
SessionConnectEvent |
STOMP CONNECT received |
SessionConnectedEvent |
CONNECT acked |
SessionSubscribeEvent |
Client subscribed |
SessionUnsubscribeEvent |
Unsubscribed |
SessionDisconnectEvent |
Closed |
11. Securing WebSocket Endpoints
Example: WebSocket authorization by destination
@Configuration
@EnableWebSocketSecurity
public class WsSecConfig {
@Bean
AuthorizationManager<Message<?>> messageAuthz(MessageMatcherDelegatingAuthorizationManager.Builder b) {
return b.simpDestMatchers("/app/admin/**").hasRole("ADMIN")
.anyMessage().authenticated()
.build();
}
}