WebSocket in Java: Creating Advanced Real-Time Applications
Modern web applications increasingly require instant data transfer between client and server. Traditional HTTP, based on request-response, is inefficient for tasks where latency is critical: online chats, stock quotes, collaborative document editing, or game servers. The WebSocket protocol solves this problem by establishing a persistent bidirectional connection. In this article, we will explore advanced techniques for working with WebSocket in Java, going beyond basic examples.
1. Architecture of an Advanced WebSocket Application in Java
A basic WebSocket example in Java using the @ServerEndpoint annotation is good for learning, but production solutions require a more robust architecture. Let's look at the key components.
1.1. Choosing the Technology Stack
For enterprise applications, the de facto standard is Spring Boot with the spring-boot-starter-websocket module. It provides integration with STOMP (Simple Text Oriented Messaging Protocol) — a sub-protocol over WebSocket that adds message routing, queues, and subscriptions.
1.2. Basic WebSocket Configuration in Spring Boot
Let's start with a configuration class:
@Configuration@EnableWebSocketMessageBrokerpublic class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override public void configureMessageBroker(MessageBrokerRegistry config) { // Built-in broker for /topic and /queue destinations config.enableSimpleBroker("/topic", "/queue"); // Prefix for messages from client to server config.setApplicationDestinationPrefixes("/app"); // Prefix for user-specific queues (point-to-point) config.setUserDestinationPrefix("/user"); }
@Override public void registerStompEndpoints(StompEndpointRegistry registry) { // Endpoint for connection via SockJS (fallback for older browsers) registry.addEndpoint("/ws") .setAllowedOrigins("*") .withSockJS(); }}This code configures connection endpoints, routing prefixes, and a built-in message broker. Using STOMP significantly simplifies working with subscriptions and queues.
2. Advanced Message Processing: From Chat to Stock Market Data
Now let's move on to implementing specific scenarios. Let's consider three typical cases: group chat, personal notifications, and data streaming.
2.1. Group Chat with Message History
A simple chat is broadcasting messages to a topic. Let's complicate the task: add message history saving and filtering by rooms.
@Controllerpublic class ChatController {
@Autowired private ChatMessageRepository repository; // JPA repository
@MessageMapping("/chat.sendMessage") @SendTo("/topic/chat/{roomId}") public ChatMessage sendMessage(@Payload ChatMessage message, @DestinationVariable String roomId, SimpMessageHeaderAccessor headerAccessor) { // Save to database message.setTimestamp(Instant.now()); repository.save(message); // Add sender info from session String username = (String) headerAccessor.getSessionAttributes().get("username"); message.setSender(username); return message; }
@MessageMapping("/chat.addUser") @SendTo("/topic/chat/{roomId}") public ChatMessage addUser(@Payload ChatMessage message, @DestinationVariable String roomId, SimpMessageHeaderAccessor headerAccessor) { headerAccessor.getSessionAttributes().put("username", message.getSender()); return message; }}Here we use