4

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

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

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

例子:

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

@MessageMapping("${myProperty}")
4

4 回答 4

2

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

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

于 2015-07-28T06:59:49.340 回答
1

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

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

为简单起见,我刚刚WebSocketAnnotationMethodMessageHandler在我的项目中创建了另一个类,位于具有相同内容的原始、org.springframework.web.socket.messaging和覆盖getMappingForMethod方法的同一包中SimpAnnotationMethodMessageHandler,仅更改SimpMessageMappingInfo使用此方法(privatein 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();
    }

}

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

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

请参阅此要点中的完整WebSocketAnnotationMethodMessageHandler实现。

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

于 2015-07-04T16:33:29.600 回答
0

更新

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

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

在此处输入图像描述

旧答案

利用

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

代替

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

并像这样使用它:

   @MessageMapping("/myHandler/{username}")
   public void handleTextMessage(@DestinationVariable String username,Message message) {
        //do something
   }
于 2015-07-04T10:46:46.697 回答
-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;
}
于 2020-03-18T19:07:34.747 回答