Implement Real‑Time Messaging with STOMP in Spring Boot

This guide explains the STOMP protocol, its frame structure, and how to integrate it with Spring Boot to build a real‑time chat application, covering server‑side configuration, message broker setup, as well as the client‑side HTML and JavaScript needed for sending and receiving messages.

Senior Brother's Insights
Senior Brother's Insights
Senior Brother's Insights
Implement Real‑Time Messaging with STOMP in Spring Boot

Introduce STOMP (Simple Text Oriented Messaging Protocol) as a simple, text‑based sub‑protocol for WebSocket that defines a frame consisting of a command, optional headers and an optional body.

STOMP Frame Structure

A typical frame looks like:

COMMAND
header1:value1
header2:value2

Body^@

Common commands include SEND, SUBSCRIBE, MESSAGE, CONNECT, CONNECTED. Headers are similar to HTTP headers (e.g., content‑type, content‑length) and the body may contain text or binary data.

Spring Boot Integration

Spring Boot provides built‑in support for STOMP over WebSocket. The following configuration enables a STOMP endpoint and a simple broker that handles destinations prefixed with /topic:

package com.secbro.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/simple")
                .setAllowedOrigins("*")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
    }
}

Two POJO classes represent the request and response payloads:

@Data
public class RequestMessage {
    private String name;
}

@Data
public class ResponseMessage {
    private String message;
}

The controller defines a STOMP message mapping and a scheduled task that pushes a counter to all subscribed clients:

@Slf4j
@RestController
public class StompController {

    private static AtomicInteger index = new AtomicInteger();

    @Resource
    private SimpMessagingTemplate messagingTemplate;

    @MessageMapping("/hello")
    @SendTo("/topic/hello")
    public ResponseMessage hello(RequestMessage message) {
        ResponseMessage resp = new ResponseMessage();
        String hello = "welcome," + message.getName() + " !";
        log.info("ResponseMessage:{}", hello);
        resp.setMessage(hello);
        return resp;
    }

    @Scheduled(fixedRate = 5000)
    public void callback() {
        messagingTemplate.convertAndSend("/topic/callback", "index: " + index.getAndIncrement());
    }
}

The main application class enables scheduling:

@EnableScheduling
@SpringBootApplication
public class SpringBootMainApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootMainApplication.class, args);
    }
}

Front‑End Page

The HTML page loads Bootstrap, jQuery, stomp.js and sockjs.min.js. It creates a SockJS connection to /simple, wraps it with Stomp, subscribes to /topic/hello and /topic/callback, and sends messages to /hello when the user clicks the send button.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>STOMP Demo</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
    <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script>
    <script src="js/stomp.js"></script>
    <script src="js/sockjs.min.js"></script>
</head>
<body class="container" style="width:70%">
    <h4>基于STOMP模式实现</h4>
    <div class="form-group">
        <textarea id="content" class="form-control" readonly cols="80" rows="15"></textarea>
    </div>
    <div class="form-group">
        <label for="message">群发消息</label>
        <input id="message" class="form-control" />
        <div style="margin-top:10px">
            <button id="user_exit" class="btn btn-danger">离开</button>
            <button id="toSend" class="btn btn-info">发送消息</button>
            <input id="username" th:value="${username}" style="display:none"/>
        </div>
    </div>
    <script type="text/javascript">
        $(document).ready(function () {
            var stompClient;
            var userName = $('#username').val();
            var socket = new SockJS('http://localhost:8080/simple');
            stompClient = Stomp.over(socket);
            stompClient.connect({}, function (frame) {
                console.log('Connected:' + frame);
                stompClient.subscribe('/topic/hello', function (response) {
                    $('#content').append(JSON.parse(response.body).message + '
');
                });
                stompClient.subscribe('/topic/callback', function (response) {
                    $('#content').append(response.body + '
');
                });
            });
            $('#toSend').click(function () { sendMsg(); });
            $(document).keyup(function (event) {
                if (event.keyCode == 13) { sendMsg(); }
            });
            function sendMsg() {
                stompClient.send("/hello", {}, JSON.stringify({'name': $('#message').val()}));
            }
            $('#user_exit').click(function () {
                if (stompClient != null) { stompClient.disconnect(); }
                $('#content').append('[' + userName + '] 已离开!');
                console.log('Disconnected');
            });
        });
    </script>
</body>
</html>

The overall flow is: the page loads, establishes a STOMP connection, subscribes to the two topics, receives periodic messages from the server, and can send messages back; clicking “离开” disconnects the client.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

real-time messagingWebSocketstompspring-boot
Senior Brother's Insights
Written by

Senior Brother's Insights

A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.

0 followers
Reader feedback

How this landed with the community

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.