消息控制器多STOMP端点识别:如何为每个@MessageMapping分配对应端点
问题解答
STOMP 端点(也就是你配置的
/ep1、/ep2)是客户端发起WebSocket握手的入口,仅作用于连接建立阶段。@MessageMapping是匹配STOMP消息的目的地址(Destination)的注解,默认和客户端连接使用的端点无绑定关系,不能直接给单个@MessageMapping指定专属的STOMP端点。
如果要实现不同端点的消息走不同的@MessageMapping处理逻辑,可以用下面两种方案:
方案1:握手拦截器标记端点来源,控制器内分支处理
这种方案改动最小,适合两个端点逻辑差异不大的场景。
- 先实现握手拦截器,在握手时记录当前使用的端点路径到会话属性:
public class EndpointHandshakeInterceptor implements HandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { // 从请求路径里提取当前匹配的端点 String path = request.getURI().getPath(); if (path.contains("/ep1")) { attributes.put("endpoint", "ep1"); } else if (path.contains("/ep2")) { attributes.put("endpoint", "ep2"); } return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { } }
- 修改WebSocket配置,给端点注册这个拦截器:
@EnableWebSocketMessageBroker @Configuration public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ep1", "/ep2") .setAllowedOriginPatterns("*") // 注册拦截器 .addInterceptors(new EndpointHandshakeInterceptor()) .withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.setApplicationDestinationPrefixes("/app"); registry.enableSimpleBroker("/topic"); } }
- 控制器内获取端点标记,分支处理:
@Controller public class StompController { @MessageMapping("/test") public void handleTest(StompHeaderAccessor headerAccessor, String payload) { String endpoint = (String) headerAccessor.getSessionAttributes().get("endpoint"); if ("ep1".equals(endpoint)) { // 处理ep1端点过来的消息 } else if ("ep2".equals(endpoint)) { // 处理ep2端点过来的消息 } } }
方案2:拆分独立的WebSocket配置,完全隔离端点路由
如果要让两个端点的处理逻辑完全隔离,互不影响,可以注册两套独立的WebSocket消息代理配置,分别绑定不同的端点和应用前缀:
// 对应ep1的配置 @Configuration @EnableWebSocketMessageBroker public class Ep1WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ep1") .setAllowedOriginPatterns("*") .withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { // 单独给ep1配置专属的应用前缀 registry.setApplicationDestinationPrefixes("/app/ep1"); registry.enableSimpleBroker("/topic/ep1"); } } // 对应ep2的配置 @Configuration @EnableWebSocketMessageBroker public class Ep2WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ep2") .setAllowedOriginPatterns("*") .withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { // 单独给ep2配置专属的应用前缀 registry.setApplicationDestinationPrefixes("/app/ep2"); registry.enableSimpleBroker("/topic/ep2"); } }
之后控制器里可以直接通过前缀区分不同端点的处理逻辑:
@Controller public class StompController { // 仅处理ep1端点过来的、目的地址为/app/ep1/test的消息 @MessageMapping("/ep1/test") public void handleEp1Test(String payload) { // ep1逻辑 } // 仅处理ep2端点过来的、目的地址为/app/ep2/test的消息 @MessageMapping("/ep2/test") public void handleEp2Test(String payload) { // ep2逻辑 } }
内容的提问来源于stack exchange,提问作者TheUser
相关产品推荐
相关产品推荐

