You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

消息控制器多STOMP端点识别:如何为每个@MessageMapping分配对应端点

问题解答

STOMP 端点(也就是你配置的/ep1、/ep2)是客户端发起WebSocket握手的入口,仅作用于连接建立阶段。@MessageMapping是匹配STOMP消息的目的地址(Destination)的注解,默认和客户端连接使用的端点无绑定关系,不能直接给单个@MessageMapping指定专属的STOMP端点。

如果要实现不同端点的消息走不同的@MessageMapping处理逻辑,可以用下面两种方案:

方案1:握手拦截器标记端点来源,控制器内分支处理

这种方案改动最小,适合两个端点逻辑差异不大的场景。

  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) {
    }
}
  1. 修改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");
    }
}
  1. 控制器内获取端点标记,分支处理:
@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 18:48:02