Real-time
Chat App
A multi-user chat room built with Spring Boot and the STOMP protocol — a hands-on exploration of WebSocket message brokering and real-time pub/sub communication.
Overview
Real-time communication requires a fundamentally different model than request–response HTTP. This project works through that model concretely using Spring WebSocket and STOMP.
Built in January 2026 as a focused learning exercise in WebSocket-based messaging. The backend runs on Spring Boot with Spring's STOMP support handling destination routing and an in-memory broker broadcasting to subscribers. The vanilla JS frontend connects via SockJS and STOMP.js — deliberately kept framework-free to keep the WebSocket mechanics visible rather than abstracted away.
Stack
Java · Spring Boot
Vanilla JS
Protocol
STOMP over WebSocket
SockJS fallback
Type
Personal · Solo
Completed
January 2026
Image Coming Soon
Message Flow
From connection to broadcast
Connect
Client opens a SockJS connection to the server. SockJS falls back from native WebSocket to HTTP long-polling if the browser or network doesn't support it.
SockJS
Subscribe
STOMP.js subscribes the client to the /topic/public channel. All broadcasts to this topic — messages, joins, and leaves — will arrive through this subscription.
STOMP.js
Join
On connect, the client sends a JOIN message to /app/chat.addUser. The controller stores the username in the WebSocket session and broadcasts a JOIN event to all subscribers.
Spring Session
Send
Chat messages are published to /app/chat.sendMessage. The Spring @MessageMapping controller receives, stamps the message, and passes it to the broker.
@MessageMapping
Broadcast
The in-memory STOMP broker fans the message out to every client subscribed to /topic/public simultaneously — no polling, no latency from HTTP overhead.
In-memory Broker
Disconnect
On disconnect, a SessionDisconnectEvent fires. The listener reads the username from the session, constructs a LEAVE message, and broadcasts it so remaining users are notified automatically.
Event Listener
Message Types
Three events, one channel
JOIN
Server → All
Broadcast when a new user connects. Triggers a join notification in every client's chat window with the new participant's name.
CHAT
Client → Server → All
A user's text message. Published by the sender to /app/chat.sendMessage, processed by the controller, then broadcast to all subscribers on /topic/public.
LEAVE
Server → All
Broadcast automatically on disconnect. The server constructs this message from the stored session without any client action — disconnecting clients can't send their own goodbye.
Features
What it implements
STOMP over WebSocket
Rather than raw WebSocket, the application uses STOMP — a simple text-based messaging protocol that adds pub/sub semantics, destination routing, and message framing on top of the WebSocket transport. This makes the server logic clean and the client simple.
SockJS Fallback
The frontend connects via SockJS, which negotiates the best available transport. Native WebSocket is used when available; HTTP long-polling serves as a reliable fallback for environments where WebSocket is blocked.
Session-based User Tracking
Usernames are stored in the WebSocket session on the JOIN event and retrieved by the disconnect listener. This means the server can attribute a departure to the right user even though disconnecting clients can no longer send messages.
Automatic Leave Notifications
Spring's SessionDisconnectEvent fires for every clean and unclean disconnect. The listener builds and broadcasts a LEAVE message automatically — no client cooperation needed, so notifications fire even on browser closes and network drops.
Color-coded User Avatars
Each participant gets a colour-coded avatar generated from their username, making it easy to visually distinguish speakers in a busy chat room without any additional identity infrastructure.
Tech Stack
Backend
- Java 17
- Spring Boot 4.0.1
- Spring WebSocket
- Lombok
Protocol
- STOMP
- SockJS (fallback)
Frontend
- Vanilla JavaScript
- HTML5 / CSS3
- STOMP.js