【问题标题】:@MessageMapping with placeholders带占位符的@MessageMapping
【发布时间】:2015-09-20 00:39:05
【问题描述】:

我正在使用 Spring-websocket,但遇到以下问题:

我试图在 @MessageMapping 注释中放置一个占位符,以便从属性中获取 url。它适用于@RequestMapping,但不适用于@MessageMapping

如果我使用此占位符,则 URL 为空。有什么想法或建议吗?

例子:

@RequestMapping(value= "${myProperty}")

@MessageMapping("${myProperty}")

【问题讨论】:

    标签: spring spring-mvc spring-websocket spring-messaging


    【解决方案1】:

    更新

    现在我明白了你的意思,但我认为这是不可能的(还)。

    Documentation 没有提及与路径映射 URI 相关的任何内容。

    旧答案

    使用

       @MessageMapping("/handler/{myProperty}")
    

    而不是

       @MessageMapping("/handler/${myProperty}")
    

    并像这样使用它:

       @MessageMapping("/myHandler/{username}")
       public void handleTextMessage(@DestinationVariable String username,Message message) {
            //do something
       }
    

    【讨论】:

    • 这不是设置URL,这只是为了传递一个参数。我想通过属性来表示 URL,我的意思是 ${myProperty} 表示完整的 URL
    【解决方案2】:

    Spring 允许您在 @RequestMapping 中使用属性占位符,但不能在 @MessageMapping 中使用。这是因为MessageHandler。因此,我们需要覆盖默认的MessageHandler 来执行此操作。

    WebSocketAnnotationMethodMessageHandler 不支持占位符,您需要自己添加此支持。

    为简单起见,我刚刚在我的项目中创建了另一个 WebSocketAnnotationMethodMessageHandler 类,位于原始 org.springframework.web.socket.messaging 的同一包中,并使用相同的内容覆盖 SimpAnnotationMethodMessageHandler 中的 getMappingForMethod 方法,仅更改 SimpMessageMappingInfo 的构造方式将此方法与此方法一起使用(WebSocketAnnotationMethodMessageHandler 中的private):

    private SimpMessageMappingInfo createMessageMappingCondition(final MessageMapping annotation) {
        return new SimpMessageMappingInfo(SimpMessageTypeMessageCondition.MESSAGE, new DestinationPatternsMessageCondition(
                this.resolveAnnotationValues(annotation.value()), this.getPathMatcher()));
    }
    
    private SimpMessageMappingInfo createSubscribeCondition(final SubscribeMapping annotation) {
        final SimpMessageTypeMessageCondition messageTypeMessageCondition = SimpMessageTypeMessageCondition.SUBSCRIBE;
        return new SimpMessageMappingInfo(messageTypeMessageCondition, new DestinationPatternsMessageCondition(
                this.resolveAnnotationValues(annotation.value()), this.getPathMatcher()));
    }
    

    这些方法现在将解析值考虑属性(调用resolveAnnotationValues 方法),所以我们需要使用这样的东西:

    private String[] resolveAnnotationValues(final String[] destinationNames) {
        final int length = destinationNames.length;
        final String[] result = new String[length];
    
        for (int i = 0; i < length; i++) {
            result[i] = this.resolveAnnotationValue(destinationNames[i]);
        }
    
        return result;
    }
    
    private String resolveAnnotationValue(final String name) {
        if (!(this.getApplicationContext() instanceof ConfigurableApplicationContext)) {
            return name;
        }
    
        final ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) this.getApplicationContext();
        final ConfigurableBeanFactory configurableBeanFactory = applicationContext.getBeanFactory();
    
        final String placeholdersResolved = configurableBeanFactory.resolveEmbeddedValue(name);
        final BeanExpressionResolver exprResolver = configurableBeanFactory.getBeanExpressionResolver();
        if (exprResolver == null) {
            return name;
        }
        final Object result = exprResolver.evaluate(placeholdersResolved, new BeanExpressionContext(configurableBeanFactory, null));
        return result != null ? result.toString() : name;
    }
    

    你仍然需要在你的配置中定义一个PropertySourcesPlaceholderConfigurer bean。

    如果您使用基于 XML 的配置,请包括以下内容:

    <context:property-placeholder location="classpath:/META-INF/spring/url-mapping-config.properties" />
    

    如果你使用的是基于Java的配置,你可以这样尝试:

    @Configuration
    @PropertySources(value = @PropertySource("classpath:/META-INF/spring/url-mapping-config.properties"))
    public class URLMappingConfig {
    
        @Bean
        public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    
    }
    

    Obs.:在这种情况下,url-mapping-config.properties 文件位于 src\main\resources\META-INF\spring 文件夹中的 gradle/maven 项目中,内容如下所示:

    myPropertyWS=urlvaluews
    

    这是我的示例控制器:

    @Controller
    public class WebSocketController {
    
        @SendTo("/topic/test")
        @MessageMapping("${myPropertyWS}")
        public String test() throws Exception {
            Thread.sleep(4000); // simulated delay
            return "OK";
        }
    
    }
    

    使用默认的MessageHandler 启动日志将打印如下内容:

    INFO: Mapped "{[/${myPropertyWS}],messageType=[MESSAGE]}" onto public java.lang.String com.brunocesar.controller.WebSocketController.test() throws java.lang.Exception
    

    现在用我们的MessageHandler 打印这个:

    INFO: Mapped "{[/urlvaluews],messageType=[MESSAGE]}" onto public java.lang.String com.brunocesar.controller.WebSocketController.test() throws java.lang.Exception
    

    在这个gist 中查看完整的WebSocketAnnotationMethodMessageHandler 实现。

    编辑:此解决方案解决了4.2 GA 之前版本的问题。如需更多信息,请参阅thisjira。

    【讨论】:

    • 它适用于@requedtmapping,但您是否为@Messagemapping 尝试过这个?
    • @bruno_cesar 你的第一个答案吓到我了:P 我在过去一小时内尝试使用 4.2.0.RC1 :P
    • @karthik 是的,对不起:P
    • 没有问题 :) (不要介意这部分,我只是在评论 15 个字符:P)
    • 您好 Bruno,我在 Jira 中添加了一个问题,其中包括 4.2 的改进。感谢您的 cmets
    【解决方案3】:

    Rossen Stoyanchev 添加了对 @MessageMapping 和 @SubscribeMapping 方法的占位符支持。

    查看 Jira 问题:https://jira.spring.io/browse/SPR-13271

    【讨论】:

      【解决方案4】:
      @MessageMapping("/chat/{roomId}")
      public Message handleMessages(@DestinationVariable("roomId") String roomId, @Payload Message message, Traveler traveler) throws Exception {
          System.out.println("Message received for room: " + roomId);
          System.out.println("User: " + traveler.toString());
      
          // store message in database
          message.setAuthor(traveler);
          message.setChatRoomId(Integer.parseInt(roomId));
          int id = MessageRepository.getInstance().save(message);
          message.setId(id);
      
          return message;
      }
      

      【讨论】:

        猜你喜欢
        • 2014-12-25
        • 1970-01-01
        • 2018-10-21
        • 2016-07-17
        • 2012-06-16
        • 2014-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多