Spring中WebSocketConfigurer addHandler中的路径参数

Posted

技术标签:

【中文标题】Spring中WebSocketConfigurer addHandler中的路径参数【英文标题】:Path Parameters in WebSocketConfigurer addHandler in Spring 【发布时间】:2018-03-20 07:43:20 【问题描述】: 我使用“TextWebSocketHandler”作为 websockets 和“WebSocketConfigurer”来配置 websocket。 我有一个场景,需要生成处理程序的不同实例。

例如:如果我正在为一些物品进行拍卖,那么我需要为每个auctionId 生成单独的WebSocketHandler 实例。 我们能否将“auctionId”作为路径参数附加到 url,以便为不同的拍卖生成不同的实例?

或者还有其他方法可以实现吗?

这就是我添加处理程序的方式:

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) 
    registry.addHandler(websocketTestHandler(), "/websocket-test");

【问题讨论】:

【参考方案1】:

如果您想使用 TextWebSocketHandler,您可以将拍卖 ID 作为 URL 路径的一部分传递。您必须在握手期间复制 WebSocket 会话的路径(这是您可以访问 ServerHttpRequest 的唯一地方,因为握手是一个 http 请求),然后从您的处理程序中检索该属性。

下面是实现:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer 

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) 
        registry.addHandler(auctionHandler(), "/auction/*")
                .addInterceptors(auctionInterceptor());
    

    @Bean
    public HandshakeInterceptor auctionInterceptor() 
        return new HandshakeInterceptor() 
            public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, 
                  WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception 

                // Get the URI segment corresponding to the auction id during handshake
                String path = request.getURI().getPath();
                String auctionId = path.substring(path.lastIndexOf('/') + 1);

                // This will be added to the websocket session
                attributes.put("auctionId", auctionId);
                return true;
            

            public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, 
                    WebSocketHandler wsHandler, Exception exception) 
                // Nothing to do after handshake
            
        ;
    

    @Bean
    public WebSocketHandler auctionHandler() 
        return new TextWebSocketHandler() 
            public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException 
                // Retrieve the auction id from the websocket session (copied during the handshake)
                String auctionId = (String) session.getAttributes().get("auctionId");

                // Your business logic...
            
        ;
    
 

客户:

new WebSocket('ws://localhost:8080/auction/1');

即使这是一个可行的解决方案,我也建议您查看STOMP over WebSockets,它会给您更多的灵活性。

【讨论】:

这个解决方案会为每个auctionId 提供一个单独的处理程序实例吗? 不,处理程序是单例的,但您可以有一个每个连接的处理程序(但不是每个auctionId 处理程序,这是特定于您的用例的,Spring 不知道) 我可以通过 cron 作业或其他方式添加这些处理程序吗?如果我能为不同的拍卖获得不同的处理程序或处理程序实例,那将非常有帮助。 最简单的方法是根据处理程序中的auctionId 委托给不同的实例【参考方案2】:

另一种选择是从会话 URI 中获取值。

请参阅下面的示例,其中我检查会话是否包含 Box 值。

URI 类似于 /chat/box

@Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
        throws IOException 

    Map<String, String> value = new Gson().fromJson(message.getPayload(), Map.class);
    String sender = value.get("sender");
    String content = value.get("content");
    String box = value.get("box");

    for (WebSocketSession webSocketSession : sessions) 

        LOGGER.info("Get messages on box  and URI ", box, session.getUri().toString());

        if (webSocketSession.getUri().toString().contains(box)) 
            webSocketSession.sendMessage(new TextMessage(sender + ": " + content + " !"));
        
    

在这种情况下,您不需要拦截器。

【讨论】:

以上是关于Spring中WebSocketConfigurer addHandler中的路径参数的主要内容,如果未能解决你的问题,请参考以下文章

Spring Day01 Spring 框架概述以及Spring中基于XML的IOC配置

学习笔记——Spring简介;Spring搭建步骤;Spring的特性;Spring中getBean三种方式;Spring中的标签

spring中 实体类在啥时候交给spring容器管理?

怎么把自己创建的对象加到spring容器中。让spring管理

如何在Maven中配置Spring依赖

Spring中如何在非Spring管理的Bean中获取到Spring管理的Bean并操作