Skip to content

Websocket Spring Boot

DodaTech 4 min read

title: "WebSocket with Spring Boot" description: "Learn how to implement WebSocket in Spring Boot applications using STOMP protocol, WebSocket handlers, and SockJS fallback." weight: 28 date: 2026-06-28 lastmod: 2026-06-28 tags: ["apis", "websocket"]


Spring Boot provides comprehensive WebSocket support through raw WebSocket handlers and the STOMP protocol sub-protocol. This lesson covers both approaches with configuration, messaging, and security.

## What You'll Learn

- Spring WebSocket configuration
- STOMP message broker setup
- WebSocket handlers
- SockJS fallback support
- WebSocket security in Spring

## Why It Matters

Spring Boot is a popular Java framework for building microservices. Native WebSocket support allows Java developers to add real-time features without additional infrastructure.

## Real-World Use

A Java-based trading platform uses Spring Boot with STOMP over WebSocket to stream real-time market data. Traders subscribe to stock symbols and receive price updates via STOMP topics.

## Flow Chart

```mermaid
flowchart LR
    A[Client] -->|STOMP over WS| B[Spring Boot Server]
    B --> C[WebSocket Handler]
    B --> D[STOMP Broker]
    C --> E[Raw WS Messages]
    D --> F[Topics / Queues]
    D --> G[Message Mapping]
    E --> H[Application Handler]
    F --> I[Subscribers]

Code Examples

Example 1: STOMP WebSocket Configuration

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.*;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // Prefix for messages from server to clients
        config.enableSimpleBroker("/topic", "/queue");
        
        // Prefix for messages from clients to server
        config.setApplicationDestinationPrefixes("/app");
        
        // Prefix for user-specific messages
        config.setUserDestinationPrefix("/user");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOrigins("https://app.example.com")
                .withSockJS(); // Enable SockJS fallback
    }
}

Expected output: Spring Boot WebSocket with STOMP broker, configured for topics and queues, with SockJS fallback for browsers that do not support WebSocket.

Example 2: STOMP Message Controller

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.beans.factory.annotation.Autowired;

@Controller
public class WebSocketController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    // Handle incoming message, broadcast to all subscribers
    @MessageMapping("/chat.sendMessage")
    @SendTo("/topic/public")
    public ChatMessage sendMessage(ChatMessage message) {
        message.setTimestamp(System.currentTimeMillis());
        return message;
    }

    // Handle typing events
    @MessageMapping("/chat.addUser")
    @SendTo("/topic/public")
    public ChatMessage addUser(ChatMessage message) {
        message.setType(ChatMessage.MessageType.JOIN);
        return message;
    }

    // Send to specific user
    @MessageMapping("/chat.private")
    public void sendPrivateMessage(ChatMessage message) {
        messagingTemplate.convertAndSendToUser(
            message.getRecipient(),
            "/queue/private",
            message
        );
    }

    // Send to specific topic
    public void broadcastUpdate(String topic, Object payload) {
        messagingTemplate.convertAndSend("/topic/" + topic, payload);
    }
}

// Message model
class ChatMessage {
    public enum MessageType { CHAT, JOIN, LEAVE }
    
    private MessageType type;
    private String content;
    private String sender;
    private String recipient;
    private long timestamp;
    // getters and setters
}

Expected output: STOMP controller handles public chat messages, user join/leave events, and private messaging via SimpMessagingTemplate.

Example 3: Spring WebSocket Security

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
            // Public endpoints
            .simpDestMatchers("/topic/public").permitAll()
            
            // Authenticated endpoints
            .simpDestMatchers("/app/**").authenticated()
            
            // User-specific destinations
            .simpDestMatchers("/user/**", "/queue/**").authenticated()
            
            // Admin-only destinations
            .simpDestMatchers("/topic/admin/**").hasRole("ADMIN")
            
            // Any other destination requires authentication
            .anyMessage().authenticated();
    }

    @Override
    protected boolean sameOriginDisabled() {
        // Allow cross-origin (needed for SockJS from different domains)
        return true;
    }
}

// JWT Authentication interceptor
@Component
public class WebSocketAuthInterceptor implements ChannelInterceptor {

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor accessor = 
            StompHeaderAccessor.wrap(message);
        
        if (StompCommand.CONNECT.equals(accessor.getCommand())) {
            String token = accessor.getFirstNativeHeader("Authorization");
            
            if (token != null && token.startsWith("Bearer ")) {
                String jwt = token.substring(7);
                try {
                    // Validate JWT and set authentication
                    Authentication auth = validateToken(jwt);
                    accessor.setUser(auth);
                } catch (Exception e) {
                    throw new AuthenticationCredentialsNotFoundException(
                        "Invalid token");
                }
            }
        }
        
        return message;
    }
}

Expected output: WebSocket messages secured with Spring Security, role-based destination access, and JWT authentication at the STOMP CONNECT frame.

Common Mistakes

Mistake Explanation
Not configuring CORS properly SockJS from different origins requires explicit CORS configuration
Using too many STOMP destinations Keep destination hierarchy simple to avoid confusion
Forgetting to enable SockJS Not all browsers support WebSocket; SockJS provides automatic fallback
Mixing raw WebSocket and STOMP Choose one approach; STOMP adds messaging semantics on top of WebSocket
Not handling session cleanup Clean up subscriptions and resources when WebSocket sessions end

Practice Questions

  1. What is the difference between STOMP and raw WebSocket?
  2. How do you configure STOMP destinations in Spring Boot?
  3. What is the purpose of SimpMessagingTemplate?
  4. How do you secure WebSocket endpoints in Spring Boot?
  5. What is SockJS and when should you use it?

Challenge

Build a Spring Boot WebSocket application for a collaborative task board. Users can create, update, and move tasks in real time. Use STOMP for messaging, Spring Security for authentication, and SockJS for browser compatibility.

FAQ

What is STOMP and why use it with WebSocket?

STOMP is a simple text-oriented messaging protocol that provides frame-based messaging, destinations, and subscription management on top of WebSocket.

How does Spring Boot handle WebSocket scaling?

Use a shared message broker like RabbitMQ or ActiveMQ Artemis with Spring's broker relay for multi-instance deployments.

Can I use STOMP without WebSocket?

Yes, STOMP can run over TCP or other transports, but WebSocket is the most common transport for web applications.

How do I handle WebSocket disconnections in Spring?

Implement SessionDisconnectEvent listener to clean up resources when a WebSocket session ends.

What is the difference between /topic and /queue destinations?

/topic uses pub-sub (one message to all subscribers), /queue uses point-to-point (one message to one consumer).

How do I test Spring WebSocket controllers?

Use Spring's MockStompFrameHandler and WebSocketStompClient for integration testing without a running server.

Mini Project

Build a real-time collaboration tool with Spring Boot WebSocket and STOMP. Implement document editing with cursor position sharing, chat, and presence indicators. Use Spring Security with JWT authentication and SockJS for browser compatibility.

What's Next

Build a complete WebSocket project

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro