Backend Development 21 min read

WebSocket Architecture Design and Implementation with Spring, SockJS, and STOMP

This article explains the principles and practical implementation of WebSocket, compares it with HTTP, discusses when to use it, and details a complete backend and frontend solution using Spring WebSocket, SockJS, and STOMP for real‑time communication in web applications.

Top Architect
Top Architect
Top Architect
WebSocket Architecture Design and Implementation with Spring, SockJS, and STOMP

Introduction

The article focuses on the core principles and practical deployment of WebSocket, describing its usage scenarios and architectural design.

WebSocket vs HTTP

HTTP follows a request‑response model (synchronous), while WebSocket establishes a TCP connection that enables full‑duplex communication, allowing both client‑to‑server and server‑to‑client messaging after the initial handshake.

Why Use WebSocket

WebSocket is ideal for web applications that require high‑frequency, low‑latency event exchange, such as online games, stock tick charts, and customer service systems.

Related Technical Concepts

WebSocket uses the ws:// (or wss:// for SSL) scheme. SockJS provides fallback transports (WebSocket, Streaming, Polling) for browsers that lack native support. STOMP (Simple Text Oriented Messaging Protocol) defines a textual message format that can be carried over WebSocket or TCP.

Backend Technical Solution

Spring WebSocket is chosen as the server‑side implementation, with SockJS enabled for compatibility and STOMP for message framing. Example configuration:

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;

public enum Role {
    CUSTOMER_SERVICE,
    CUSTOMER;
}

public static boolean isCustomer(User user) {
    Collection<GrantedAuthority> authorities = user.getAuthorities();
    SimpleGrantedAuthority customerGrantedAuthority = new SimpleGrantedAuthority("ROLE_" + Role.CUSTOMER.name());
    return authorities.contains(customerGrantedAuthority);
}

public static boolean isCustomerService(User user) {
    Collection<GrantedAuthority> authorities = user.getAuthorities();
    SimpleGrantedAuthority customerServiceGrantedAuthority = new SimpleGrantedAuthority("ROLE_" + Role.CUSTOMER_SERVICE.name());
    return authorities.contains(customerServiceGrantedAuthority);
}

Spring Security in‑memory users are configured as:

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles(Role.CUSTOMER_SERVICE.name());
        auth.inMemoryAuthentication().withUser("user").password("user").roles(Role.CUSTOMER.name());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .formLogin()
            .and()
            .authorizeRequests().anyRequest().authenticated();
    }
}

WebSocket endpoints and broker are set up as:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/portfolio").withSockJS();
    }
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.setApplicationDestinationPrefixes("/app");
        config.enableSimpleBroker("/topic", "/queue");
    }
}

Frontend Technical Solution

The client uses SockJS and stomp.js libraries:

<script src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.min.js"></script>
<script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script>
<script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>

var socket = new SockJS("/portfolio");
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
    console.log("Connected: " + frame.headers["user-name"]);
});

Message handling on the server side uses @MessageMapping and @SendToUser annotations. Example controller:

@Controller
public class ChatWebSocket {
    @MessageMapping("broadcast")
    public String broadcast(@Payload @Validated Message message, Principal principal) {
        return "Sender: " + principal.getName() + " Content: " + message.toString();
    }
}

@Data
public class Message {
    @NotNull(message = "Title cannot be empty")
    private String title;
    private String content;
}

One‑to‑one communication (e.g., customer‑service chat) uses user‑specific destinations:

@MessageMapping("/queue/chat/{uid}")
public void chat(@Payload @Validated Message message, @DestinationVariable("uid") String uid, Principal principal) {
    String msg = "Sender: " + principal.getName() + " chat";
    simpMessagingTemplate.convertAndSendToUser(uid, "/queue/chat", msg);
}

Exception handling for validation errors is performed with @MessageExceptionHandler:

@MessageExceptionHandler
@SendToUser(value = "/queue/error", broadcast = false)
public String handleException(MethodArgumentNotValidException ex) {
    BindingResult result = ex.getBindingResult();
    if (!result.hasErrors()) return "Unknown error";
    return "Validation error: " + result.getFieldError().getDefaultMessage();
}

Application Scenario

The article illustrates a customer service system where users and agents are assigned roles, their online/offline states are managed, and relationships are stored via an abstract RelationHandler. A facade (UserManagerFacade) coordinates distribution, state management, and relation handling, demonstrating the Facade design pattern.

Conclusion

The piece provides a thorough overview of WebSocket fundamentals, compares it with HTTP, and walks through a complete end‑to‑end implementation using Spring, SockJS, and STOMP, emphasizing the importance of understanding the underlying theory before coding.

Backend DevelopmentspringWebSocketreal-time communicationSTOMPSockJS
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.