Push live updates to the browser. Add WebSocket support to the Bookstore, handle raw text messages, register the endpoint, broadcast order updates over STOMP, and connect from the browser.
Why: a normal HTTP request is one-way and one-shot — the client asks, the server answers, the connection closes. That cannot push anything to a user who is just sitting on a page. A WebSocket is a single connection that stays open so the server can send updates (a shipped order, a price change) the moment they happen. Note: spring-boot-starter-websocket adds everything you need.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>Why: the simplest approach is a handler that reacts to raw text messages. Extend TextWebSocketHandler and override handleTextMessage — Spring calls it every time a client sends something. Here it echoes the message back; afterConnectionEstablished fires when a client joins.
@Component
public class EchoHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) {
System.out.println("a client connected: " + session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message)
throws Exception {
session.sendMessage(new TextMessage("you said: " + message.getPayload()));
}
}Why: a handler does nothing until you map it to a URL path. @EnableWebSocket plus a WebSocketConfigurer tells Spring which handler answers which endpoint. Note: setAllowedOrigins controls which websites may connect — never leave it as "*" in production.
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final EchoHandler echoHandler;
public WebSocketConfig(EchoHandler echoHandler) {
this.echoHandler = echoHandler;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(echoHandler, "/ws/echo")
.setAllowedOrigins("https://your-frontend.example");
}
}When: raw handlers are fine for one-to-one echoes, but broadcasting to many clients by hand is tedious. STOMP is a small messaging protocol Spring supports on top of WebSockets — clients subscribe to a "topic" and you publish to it, and Spring delivers to everyone subscribed. Note: @EnableWebSocketMessageBroker turns it on; the simple in-memory broker is enough to start.
// config: a STOMP endpoint clients connect to, and a broker
@Configuration
@EnableWebSocketMessageBroker
public class StompConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("https://your-frontend.example");
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic"); // where clients subscribe
registry.setApplicationDestinationPrefixes("/app"); // where they send
}
}// push an update to everyone subscribed to /topic/orders
@Service
public class OrderNotifier {
private final SimpMessagingTemplate messaging;
public OrderNotifier(SimpMessagingTemplate messaging) {
this.messaging = messaging;
}
public void orderShipped(Order order) {
messaging.convertAndSend("/topic/orders", order); // sent as JSON
}
}Why: this is the other half — a browser connects to the raw /ws/echo endpoint with the built-in WebSocket object, sends a message, and logs replies. Note: this snippet is JavaScript that runs in the browser, not Java. (A STOMP endpoint instead uses a client library such as @stomp/stompjs.)
const socket = new WebSocket('wss://your-api.example/ws/echo')
socket.onopen = () => socket.send('Hello from the browser!')
socket.onmessage = (event) => {
console.log('server says:', event.data)
}