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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27047310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 03:44:06  来源:igfitidea点击:

Path variables in Spring WebSockets @SendTo mapping

javaspringwebsocketstompsockjs

提问by bvulaj

I have, what I think to be, a very simple Spring WebSocket application. However, I'm trying to use path variables for the subscription as well as the message mapping.

我有一个非常简单的 Spring WebSocket 应用程序。但是,我正在尝试将路径变量用于订阅以及消息映射。

I've posted a paraphrased example below. I would expect the @SendToannotation to return back to the subscribers based on their fleetId. ie, a POSTto /fleet/MyFleet/driver/MyDrivershould notify subscribers of /fleet/MyFleet, but I'm not seeing this behavior.

我在下面发布了一个释义示例。我希望@SendTo注释会根据订阅者的fleetId. 即, a POSTto/fleet/MyFleet/driver/MyDriver应该通知订阅者/fleet/MyFleet,但我没有看到这种行为。

It's worth noting that subscribing to literal /fleet/{fleetId}works. Is this intended? Am I missing some piece of configuration? Or is this just not how it works?

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

I'm not very familiar with WebSockets or this Spring project yet, so thanks in advance.

我对 WebSockets 或这个 Spring 项目还不是很熟悉,所以提前致谢。

Controller.java

控制器.java

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

WebSocketConfig.java

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();
    }
}

index.html

索引.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
    });
});

Send Sample

发送样品

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

采纳答案by Sergi Almar

Even though @MessageMappingsupports placeholders, they are not exposed / resolved in @SendTodestinations. Currently, there's no way to define dynamic destinations with the @SendToannotation (see issue SPR-12170). You could use the SimpMessagingTemplatefor the time being (that's how it works internally anyway). Here's how you would do it:

即使@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));
}

In your code, the destination '/topic/fleet/{fleetId}' is treated as a literal, that's the reason why subscribing to it works, just because you are sending to the exact same destination.

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

If you just want to send some initial user specific data, you could return it directly in the subscription:

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

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

Update:In Spring 4.2, destination variable placeholders are supported it's now possible to do something like:

更新:在 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);
}

回答by ivan rc

you can send a variable inside the path. for example i send "este/es/el/chat/java/" and obtaned in the server as "este:es:el:chat:java:"

您可以在路径内发送一个变量。例如,我发送“este/es/el/chat/java/ ”并在服务器中获得“este:es:el:chat:java:

client:

客户:

stompSession.send("/app/chat/este/es/el/chat/java/*", ...);

server:

服务器:

@MessageMapping("/chat/**")
@SendToUser("/queue/reply")
public WebsocketData greeting(Message m,HelloMessage message,@Header("simpSessionId") String sessionId) throws Exception {
    Map<String, LinkedList<String>> nativeHeaders = (Map<String, LinkedList<String>>) m.getHeaders().get("nativeHeaders");
    String value= nativeHeaders.get("destination").getFirst().replaceAll("/app/chat/","").replaceAll("/",":");

回答by Jo?o Rodrigues

Actually I think this is what you might be looking for:

实际上,我认为这就是您可能正在寻找的内容:

@Autorwired
lateinit var template: SimpMessageTemplate;

@MessageMapping("/class/{id}")
@Throws(Exception::class)
fun onOffer(@DestinationVariable("id") id: String?, @Payload msg: Message) {
    println("RECEIVED " + id)
    template.convertAndSend("/topic/class/$id", Message("The response"))
}

Hope this helps someone! :)

希望这可以帮助某人!:)