Spring WebSockets @SendTo映射中的路径变量

bvu*_*laj 36 java spring stomp websocket sockjs

我有,我认为是一个非常简单的Spring WebSocket应用程序.但是,我正在尝试使用路径变量进行订阅以及消息映射.

我在下面发布了一个释义的例子.我希望@SendTo注释能够根据用户返回给订阅者fleetId.即POST/fleet/MyFleet/driver/MyDriver应通知用户/fleet/MyFleet,但我没有看到这种行为.

值得注意的是订阅文字/fleet/{fleetId}作品.这是有意的吗?我错过了一些配置吗?或者这不是它的工作原理吗?

我对WebSockets或Spring项目不是很熟悉,所以提前谢谢.

Controller.java

...
@MessageMapping("/fleet/{fleetId}/driver/{driverId}")
@SendTo("/topic/fleet/{fleetId}")
public Simple simple(@DestinationVariable String fleetId, @DestinationVariable String driverId) {
    return new Simple(fleetId, driverId);
}
...
Run Code Online (Sandbox Code Playgroud)

WebSocketConfig.java

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/live");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/fleet").withSockJS();
    }
}
Run Code Online (Sandbox Code Playgroud)

的index.html

var socket = new SockJS('/fleet');
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
    // Doesn't Work
    stompClient.subscribe('/topic/fleet/MyFleet', function(greeting) {
    // Works
    stompClient.subscribe('/topic/fleet/{fleetId}', function(greeting) {
        // Do some stuff
    });
});
Run Code Online (Sandbox Code Playgroud)

发送样品

    stompClient.send("/live/fleet/MyFleet/driver/MyDriver", {}, JSON.stringify({
        // Some simple content
    }));
Run Code Online (Sandbox Code Playgroud)

Ser*_*mar 91

即使@MessageMapping支持占位符,它们也不会在@SendTo目标中公开/解析.目前,无法使用@SendTo注释定义动态目标(请参阅问题SPR-12170).你可以SimpMessagingTemplate暂时使用它(无论如何它都在内部工作).这是你如何做到的:

@MessageMapping("/fleet/{fleetId}/driver/{driverId}")
public void simple(@DestinationVariable String fleetId, @DestinationVariable String driverId) {
    simpMessagingTemplate.convertAndSend("/topic/fleet/" + fleetId, new Simple(fleetId, driverId));
}
Run Code Online (Sandbox Code Playgroud)

在您的代码中,目标' / topic/fleet/{fleetId} '被视为文字,这就是订阅它的原因,因为您发送到完全相同的目的地.

如果您只想发送一些初始用户特定数据,可以直接在订阅中返回:

@SubscribeMapping("/fleet/{fleetId}/driver/{driverId}")
public Simple simple(@DestinationVariable String fleetId, @DestinationVariable String driverId) {
    return new Simple(fleetId, driverId);
}
Run Code Online (Sandbox Code Playgroud)

更新: 在Spring 4.2中,支持目标变量占位符,现在可以执行以下操作:

@MessageMapping("/fleet/{fleetId}/driver/{driverId}")
@SendTo("/topic/fleet/{fleetId}")
public Simple simple(@DestinationVariable String fleetId, @DestinationVariable String driverId) {
    return new Simple(fleetId, driverId);
}
Run Code Online (Sandbox Code Playgroud)

  • `@SubsMapping`只拦截订阅(不是消息到通道),返回值将直接发送给用户,但可以用`@ SendTo`覆盖,将其发送到另一个目的地(将被转发到brokerChannel).`@ SendTo`也可以与`@MessageMapping`一起使用,将响应发送到特定目的地.所以基本上,`@ SendTo`可以与`@ MessageMapping`和`@ SubscribeMapping`一起使用 (2认同)
  • 感谢您对此答案的更新,这真的很有帮助! (2认同)
  • @JordanMackie 检查 https://github.com/salmar/spring-websocket-chat/blob/c77467a77905abc24100d4e8040158c450d12a79/src/main/java/com/sergialmar/wschat/web/ChatController.java#L54 (2认同)