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.
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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'.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
