Spring Boot 3.3 搭配 STOMP,轻松实现数据实时通信

在现代 Web 应用中,实时通信越来越重要。传统的 HTTP 请求-响应模型已经无法满足某些实时性要求较高的应用场景,如在线聊天、通知推送、实时数据更新等。为了解决这个问题,我们可以利用 WebSocket 技术,而 STOMP 协议则可以进一步简化 WebSocket 的使用。本文将通过 Spring Boot 3.3 和 STOMP 协议的结合,构建一个高效的实时数据通信系统。

什么是 STOMP 协议?

STOMP(Streaming Text Oriented Messaging Protocol)是一种简单的文本消息协议,类似于 HTTP。它定义了如何通过网络协议进行消息的发送和接收。在 WebSocket 的基础上使用 STOMP 协议可以极大地简化消息的处理,使得消息系统更加结构化、可扩展且易于管理。

STOMP 协议的优势

  • 简单易用:STOMP 使用文本格式,非常容易解析和调试。

  • 消息订阅/发布:通过 SUBSCRIBE 和 UNSUBSCRIBE 命令可以轻松实现消息的订阅和取消订阅。

  • 兼容性好:STOMP 支持与现有的消息代理系统(如 ActiveMQ、RabbitMQ)配合使用。

  • 跨语言支持:STOMP 不依赖于特定语言,允许不同语言的客户端通过 STOMP 通信。

项目配置

在本文的示例中,我们将使用 Spring Boot 3.3 和 STOMP 实现一个简单的实时通信应用,包括消息的发送、异步处理和发布/订阅机制。前端页面使用 jQuery 和 Bootstrap,通过 HTTP 方式直接引用。

运行效果:

在现代 Web 应用中,实时通信越来越重要。传统的 HTTP 请求-响应模型已经无法满足某些实时性要求较高的应用场景,如在线聊天、通知推送、实时数据更新等。为了解决这个问题,我们可以利用 WebSocket 技术,而 STOMP 协议则可以进一步简化 WebSocket 的使用。本文将通过 Spring Boot 3.3 和 STOMP 协议的结合,构建一个高效的实时数据通信系统。

什么是 STOMP 协议?

STOMP(Streaming Text Oriented Messaging Protocol)是一种简单的文本消息协议,类似于 HTTP。它定义了如何通过网络协议进行消息的发送和接收。在 WebSocket 的基础上使用 STOMP 协议可以极大地简化消息的处理,使得消息系统更加结构化、可扩展且易于管理。

STOMP 协议的优势

  • 简单易用:STOMP 使用文本格式,非常容易解析和调试。

  • 消息订阅/发布:通过 SUBSCRIBE 和 UNSUBSCRIBE 命令可以轻松实现消息的订阅和取消订阅。

  • 兼容性好:STOMP 支持与现有的消息代理系统(如 ActiveMQ、RabbitMQ)配合使用。

  • 跨语言支持:STOMP 不依赖于特定语言,允许不同语言的客户端通过 STOMP 通信。

项目配置

在本文的示例中,我们将使用 Spring Boot 3.3 和 STOMP 实现一个简单的实时通信应用,包括消息的发送、异步处理和发布/订阅机制。前端页面使用 jQuery 和 Bootstrap,通过 HTTP 方式直接引用。

运行效果:

 若想获取项目完整代码以及其他文章的项目源码,且在代码编写时遇到问题需要咨询交流,欢迎加入下方的知识星球。


项目依赖配置 (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.icoderoad</groupId>
	<artifactId>stomp_demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>stomp_demo</name>
	<description>Demo project for Spring Boot</description>
	
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		
		<!-- Spring Boot Starter WebSocket -->
	    <dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-websocket</artifactId>
	    </dependency>
	
	    <!-- Spring Boot Starter Web -->
	    <dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-web</artifactId>
	    </dependency>
	
	    <!-- Thymeleaf for HTML templates -->
	    <dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-thymeleaf</artifactId>
	    </dependency>
	    
		 <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

配置文件 application.yml

server:
  port: 8080
  
app:
  websocketEndpoint: /websocket-endpoint
  simpleBrokerDestinations:
    - /topic
    - /queue
  applicationDestinationPrefix: /app

属性配置类 (AppProperties)

我们将 WebSocket 相关的配置信息放入一个属性类 AppProperties,这样可以更灵活地管理这些参数。

package com.icoderoad.stompdemo.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import lombok.Data;

@Data
@Configuration
@ConfigurationProperties(prefix = "app")
public class AppProperties {
	
    private String websocketEndpoint;
    
    private String[] simpleBrokerDestinations;
    
    private String applicationDestinationPrefix;
    
}

 

WebSocket 配置类 (WebSocketConfig)

我们使用 WebSocketMessageBrokerConfigurer 来配置 WebSocket。AppProperties 中的配置将通过 @Autowired 自动注入到 WebSocketConfig 中。

package com.icoderoad.stompdemo.config;

import org.springframework.beans.factory.annotation.Autowired;
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 {

    @Autowired
    private AppProperties appProperties;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker(appProperties.getSimpleBrokerDestinations());
        config.setApplicationDestinationPrefixes(appProperties.getApplicationDestinationPrefix());
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint(appProperties.getWebsocketEndpoint()).withSockJS();
    }
}

Message 类

package com.icoderoad.stompdemo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Message {
    private String content;
}

消息处理控制器 (MessageController)

在这里,我们定义了不同的消息处理方法,包括异步处理和发布/订阅模式。

package com.icoderoad.stompdemo.config;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;

import com.icoderoad.stompdemo.entity.Message;

@Controller
public class MessageController {

    // 简单的消息发送,接收 JSON 对象并返回
    @MessageMapping("/send")
    @SendTo("/topic/messages")
    public Message send(Message message) {
        return message; // 原样返回消息
    }

    // 异步消息处理
    @MessageMapping("/asyncMessage")
    @SendTo("/topic/asyncMessages")
    public ListenableFuture<Message> asyncMessage(Message message) {
        ListenableFutureTask<Message> futureTask = new ListenableFutureTask<>(() -> {
            // 模拟一些处理
            Thread.sleep(2000);
            return message;
        });
        new Thread(futureTask).start();
        return futureTask;
    }

    // 发布/订阅模式
    @MessageMapping("/broadcast")
    @SendTo("/topic/broadcasts")
    public String broadcast(String content) {
        return "广播消息: " + content;
    }

    // 处理带异常的消息
    @MessageMapping("/errorHandling")
    @SendTo("/queue/errors")
    public Message handleError(Message message) throws Exception {
        if ("error".equalsIgnoreCase(message.getContent())) {
            throw new Exception("消息包含错误内容");
        }
        return message;
    }
}

视图控制类

package com.icoderoad.stompdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {

    @GetMapping("/")
    public String index() {
        return "index";
    }
    
}

前端页面 (index.html)

前端页面使用 Bootstrap 和 jQuery 进行样式和交互,并通过 HTTP 方式直接引入外部资源。

在 src/main/resources/templates 目录下创建 index.html 文件:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>STOMP 实时通信示例</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1.5.1/dist/sockjs.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
</head>
<body>
<div class="container">
    <h1 class="text-center">STOMP 实时通信示例</h1>

    <!-- 输入消息框 -->
    <div class="form-group">
        <label for="messageInput">消息内容:</label>
        <input type="text" id="messageInput" class="form-control" placeholder="输入消息">
    </div>
    
    <!-- 发送简单消息按钮 -->
    <button id="sendButton" class="btn btn-primary mt-2">发送消息</button>

    <!-- 发送异步消息按钮 -->
    <button id="sendAsyncButton" class="btn btn-success mt-2">发送异步消息</button>

    <!-- 发送发布订阅消息按钮 -->
    <button id="broadcastButton" class="btn btn-warning mt-2">发送广播消息</button>

    <!-- 显示接收到的消息 -->
    <h3 class="text-center mt-5">接收到的消息:</h3>
    <div id="messageContainer" class="border p-3"></div>
</div>

<script type="text/javascript">
    var stompClient = null;

    // 建立 WebSocket 连接
    function connect() {
        var socket = new SockJS('/websocket-endpoint');
        stompClient = Stomp.over(socket);

        stompClient.connect({}, function(frame) {
            console.log('已连接: ' + frame);

            // 订阅消息主题
            stompClient.subscribe('/topic/messages', function(message) {
                showMessage(JSON.parse(message.body).content);
            });

            // 订阅异步消息主题
            stompClient.subscribe('/topic/asyncMessages', function(message) {
                showMessage("异步消息: " + JSON.parse(message.body).content);
            });

            // 订阅广播消息
            stompClient.subscribe('/topic/broadcasts', function(message) {
                showMessage("广播消息: " + message.body);
            });
        });
    }

    // 显示消息
    function showMessage(message) {
        $("#messageContainer").append("<p>" + message + "</p>");
    }

    // 发送消息
    $("#sendButton").click(function() {
        var message = {content: $("#messageInput").val()};
        stompClient.send("/app/send", {}, JSON.stringify(message));
    });

    // 发送异步消息
    $("#sendAsyncButton").click(function() {
        var message = {content: $("#messageInput").val()};
        stompClient.send("/app/asyncMessage", {}, JSON.stringify(message));
    });

    // 发送广播消息
    $("#broadcastButton").click(function() {
        stompClient.send("/app/broadcast", {}, $("#messageInput").val());
    });

    // 连接 WebSocket
    connect();
</script>
</body>
</html>

总结

本文详细介绍了如何在Spring Boot 3.3中结合STOMP协议实现实时数据通信。我们通过配置WebSocket支持、创建消息控制器、构建前端界面,并结合@ConfigurationProperties进行配置管理,实现了一个功能完备的实时消息系统。STOMP协议提供的简化消息传输和高效通信的优势,使得它成为构建实时Web应用的理想选择。希望通过本文,大家能掌握如何在 Spring Boot3.3 项目中利用 STOMP 协议简化实时通信的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值