导读:本期聚焦于刘卫东创作的《Spring Boot整合WebSocket STOMP如何实现服务端消息推送?完整配置与代码示例详解》,敬请观看详情。服务端主动向客户端推送消息是实时应用的核心需求,普通WebSocket虽然能建立双向连接,但缺少消息路由、订阅管理等机制。STOMP协议在WebSocket之上提供了一层基于发布订阅模型的消息语义,配合Spring Boot的spring-websocket模块,可以快速构建带消息代理的实时通信服务。本文将围绕Spring Boot整合STOMP的完整流程展开,包括依赖引入、STOMP端点与消息代理配置、服务端使用SimpMessagingTemplate主动推送消息、前端通过stompjs订阅消息的具体写法,同时分析点对点推送、广播推送的实现差异,以及跨域、心跳、拦截器认证等常见问题的处理方案,帮助你搭建稳定可靠的实时消息通道。

STOMP(Simple Text Oriented Messaging Protocol)是一个建立在WebSocket之上的简单文本消息协议,它为原始的WebSocket连接增加了发布订阅语义。原始的WebSocket只提供了一条裸连接,服务端和客户端虽然可以互发数据,但消息该发给谁、发到哪个目的地,都需要开发者自己设计协议。而STOMP通过SEND、SUBSCRIBE、MESSAGE等固定帧格式,让消息具备路由能力,配合Spring内置的消息代理,实现广播和点对点推送变得非常简单。下面详细介绍Spring Boot整合STOMP的完整过程。

Spring Boot整合WebSocket STOMP如何实现服务端消息推送?完整配置与代码示例详解

一、为什么选择STOMP而不是裸WebSocket

裸WebSocket的通信模型很简单:一个连接对应一个会话,服务端要给某个用户发消息,就必须自己维护Session与用户的映射关系,一旦连接数量增大,管理成本会明显上升。同时浏览器端的代码也需要自己解析消息格式,判断这条消息属于哪种业务类型,扩展性比较差。

STOMP在WebSocket之上抽象出三类核心角色:客户端可以SUBSCRIBE订阅某个目的地,可以SEND向某个目的地发送消息;消息代理负责根据目的地把消息分发给所有订阅者。这种模型天然适合聊天室、站内通知、监控大屏推送等场景。比如一个股票行情系统,客户端只需订阅/topic/stock/AAPL,服务端往这个目的地推消息,所有订阅者都能收到,完全不需要手动管理连接列表。

Spring对STOMP的支持非常完善,spring-websocketspring-messaging两个模块提供了完整的注解驱动编程模型。开发者可以用@MessageMapping处理客户端发来的消息,用SimpMessagingTemplate主动推送消息,开发体验和写普通Controller几乎没有区别。

二、服务端整合与核心配置

首先在pom.xml中引入相关依赖,Spring Boot已经把WebSocket相关内容打成了一个starter,直接引入即可:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

接下来编写WebSocket配置类,这是整个整合的核心。配置类需要继承WebSocketMessageBrokerConfigurer,重点实现两个方法:registerStompEndpoints注册STOMP端点,configureMessageBroker配置消息代理规则。

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOriginPatterns("*")
                .withSockJS(); // 开启SockJS降级支持
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 客户端订阅前缀,消息代理会处理以/topic和/queue开头的订阅
        registry.enableSimpleBroker("/topic", "/queue");
        // 客户端发送消息的前缀,发往前缀下的目的地会进入@MessageMapping方法
        registry.setApplicationDestinationPrefixes("/app");
        // 点对点推送时使用的用户前缀
        registry.setUserDestinationPrefix("/user");
    }
}

上面的配置里有几个关键点需要理解。/ws是WebSocket握手端点,客户端连接的就是这个地址。enableSimpleBroker启用的是内置的内存消息代理,适合单机应用;如果需要集群部署,可以改用enableStompBrokerRelay连接外部的RabbitMQ或ActiveMQ,这样多台服务节点可以共享消息。setApplicationDestinationPrefixes指定的/app前缀很关键,客户端发送到/app/hello的消息会被路由到@MessageMapping("/hello")标注的方法,而不是直接进入消息代理。

三、服务端接收消息与主动推送

服务端处理客户端消息使用@MessageMapping注解,功能类似MVC中的@RequestMapping。方法的返回值可以通过@SendTo指定推送到某个目的地,也可以注入SimpMessagingTemplate获得更灵活的推送能力。

@Controller
public class MessageController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    // 处理客户端发到 /app/hello 的消息,并广播到 /topic/greetings
    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(HelloMessage message) throws Exception {
        Thread.sleep(1000); // 模拟处理耗时
        return new Greeting("Hello, " + message.getName() + "!");
    }

    // 主动推送,适合在业务Service中调用
    public void pushToUser(String userId, String payload) {
        // 点对点:只有指定用户能收到
        messagingTemplate.convertAndSendToUser(userId, "/queue/notify", payload);
    }

    public void pushBroadcast(String payload) {
        // 广播:所有订阅了/topic/notice的客户端都能收到
        messagingTemplate.convertAndSend("/topic/notice", payload);
    }
}

广播推送和点对点推送的实现方式有明显差异。广播直接调用convertAndSend,目的地以/topic开头,所有订阅者共享同一条消息。点对点推送调用convertAndSendToUser,框架会自动在目的地前面拼上用户前缀,实际发往类似/user/{userId}/queue/notify的地址,而客户端只需要订阅/user/queue/notify即可,Spring会自动完成用户与订阅的匹配。如果同一个用户开了多个浏览器标签页,每个连接都会收到消息,这符合大多数业务场景的预期。

四、前端连接与订阅消息

前端推荐使用sockjs-client和stompjs这两个库。SockJS提供了浏览器兼容降级,在WebSocket不可用时会自动切换到xhr-streaming等替代方案。客户端代码的基本流程是:建立连接、订阅目的地、发送消息。

var socket = new SockJS('http://127.0.0.1:8080/ws');
var stompClient = Stomp.over(socket);

stompClient.connect({}, function (frame) {
    // 订阅广播消息
    stompClient.subscribe('/topic/notice', function (message) {
        console.log('收到广播: ' + message.body);
    });

    // 订阅个人消息,框架自动处理用户前缀
    stompClient.subscribe('/user/queue/notify', function (message) {
        console.log('收到私信: ' + message.body);
    });
});

// 向服务端发送消息,会被@MessageMapping("/hello")处理
function sendHello() {
    stompClient.send("/app/hello", {}, JSON.stringify({name: '张三'}));
}

需要注意的是,点对点推送要求服务端知道当前连接属于哪个用户。最简单的做法是在握手阶段通过URL参数传递用户标识,并配合HandshakeInterceptor把用户信息放入WebSocket会话,再自定义Principal解析逻辑。如果系统已经集成了Spring Security,基于HTTP会话的认证可以自然延伸到WebSocket连接上,convertAndSendToUser就能直接使用登录用户的身份。

五、常见问题与生产实践建议

跨域问题是整合时最常踩的坑。浏览器发起WebSocket握手时同样受同源策略限制,如果前后端不同源,必须调用setAllowedOriginPatterns("*")或指定具体域名,否则握手会直接失败。生产环境建议写明白名单域名,不要长期保留星号。

心跳配置也值得关注。STOMP协议自带心跳机制,可以在configureWebSocketTransport中设置服务端心跳间隔。没有心跳的情况下,如果客户端网络异常断开,服务端可能长时间感知不到,造成僵尸连接和消息推送失败。配置心跳后,连续几个周期没有收到对方心跳就会被判定为断连,触发资源清理。

认证与安全方面,建议通过ChannelInterceptor拦截CONNECT帧,从STOMP头部中取出token进行校验,校验通过后再放行后续订阅。同时要限制订阅权限,比如普通用户不允许订阅管理员专属的/topic/admin,可以在subscribe阶段做拦截校验,防止越权获取消息。集群部署时记得把内置SimpleBroker换成外部消息代理,否则消息只会在单节点内分发,不同节点上的用户互相收不到消息。只要把这些细节处理好,STOMP方案完全可以支撑中等规模系统的实时消息需求。

Spring Boot STOMPWebSocket消息推送SpringMessaging修改时间:2026-09-10 21:44:57

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260910/54286.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。