带有占位符的@MessageMapping

时间:2015-07-02 12:57:30

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

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

我正在尝试将占位符放在@MessageMapping注释中,以便从属性中获取网址。它适用于@RequestMapping,但不适用于@MessageMapping

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

示例:

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

@MessageMapping("${myProperty}")

4 个答案:

答案 0 :(得分:2)

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

请参阅Jira问题:https://jira.spring.io/browse/SPR-13271

答案 1 :(得分:1)

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

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

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

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之前版本的问题。有关详细信息,请参阅this jira。

答案 2 :(得分:0)

更新

现在我明白了你的意思,但我认为那是不可能的。

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

enter image description here

旧答案

使用

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

而不是

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

并像这样使用它:

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

答案 3 :(得分:-1)

@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;
}