Variables de ruta en Spring WebSockets @SendTo mapeo

4 minutos de lectura

Tengo, lo que creo que es, una aplicación Spring WebSocket muy simple. Sin embargo, estoy tratando de usar variables de ruta para la suscripción y el mapeo de mensajes.

He publicado un ejemplo parafraseado a continuación. Yo esperaría el @SendTo anotación para volver a los suscriptores en función de su fleetId. es decir, un POST a /fleet/MyFleet/driver/MyDriver debe notificar a los suscriptores de /fleet/MyFleetpero no veo este comportamiento.

Vale la pena señalar que suscribirse a literal /fleet/{fleetId} obras. ¿Es esto intencionado? ¿Me estoy perdiendo alguna pieza de configuración? ¿O simplemente no es así como funciona?

Todavía no estoy muy familiarizado con WebSockets o este proyecto Spring, así que gracias de antemano.

Controlador.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

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

índice.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
    });
});

Enviar muestra

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

Avatar de usuario de Sergi Almar
Sergi Almar

A pesar de @MessageMapping admite marcadores de posición, no están expuestos / resueltos en @SendTo destinos Actualmente, no hay manera de definir destinos dinámicos con el @SendTo anotación (ver tema SPR-12170). Podrías usar el SimpMessagingTemplate por el momento (así es como funciona internamente de todos modos). Así es como lo harías:

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

En su código, el destino ‘/tema/flota/{fleetId}‘ se trata como un literal, esa es la razón por la cual la suscripción funciona, solo porque está enviando exactamente al mismo destino.

Si solo desea enviar algunos datos iniciales específicos del usuario, puede devolverlos directamente en la suscripción:

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

Actualizar:
En Spring 4.2, se admiten marcadores de posición de variables de destino; ahora es posible hacer algo como:

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

  • Gracias, @sergi! Tenía la esperanza de poder usar MessagingTempalte, pero funciona igual de bien. ¿Cuál es la diferencia entre usar @SubscribeMapping y @SendTo? ¿El primero simplemente se salta el intermediario de mensajes?

    – bvulaj

    21 de noviembre de 2014 a las 14:17

  • @SubscribeMapping intercepta solo suscripciones (no mensajes al canal), el valor de retorno se enviará directamente al usuario, pero se puede anular con @SendTo para enviarlo a otro destino (se reenviará al brokerChannel). @SendTo también se puede utilizar con @MessageMapping para enviar la respuesta a un destino específico. Así que básicamente, @SendTo se puede usar junto con @MessageMapping y @SubscribeMapping

    – Sergio Almar

    21 de noviembre de 2014 a las 15:40


  • Debo hacer el mismo proyecto, pero no puedo comenzar, lo mismo tiene un proyecto de prototipo que se puede usar, en github, por ejemplo. Sé que trabajo Spring pero no trabajo WebSocket, necesito enviar un mensaje a dos personas y el mensaje es igual a Skype. uno a uno, árbol si invita a más comunicaciones de un usuario

    –Marcelo Ferreira

    15 de diciembre de 2016 a las 18:11

  • Gracias por sus actualizaciones sobre esta respuesta, ¡fue realmente útil!

    – Vladlen Gladis

    16 de diciembre de 2016 a las 12:55

  • @JordanMackie cheque github.com/salmar/spring-websocket-chat/blob/…

    – Sergio Almar

    28 de junio de 2018 a las 12:29

puede enviar una variable dentro de la ruta. por ejemplo mando “este/es/el/chat/java/” y se obtiene en el servidor como “este:es:el:chat:java:

cliente:

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

servidor:

@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("https://stackoverflow.com/",":");

De hecho, creo que esto es lo que podrías estar buscando:

@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"))
}

¡Espero que esto ayude a alguien! 🙂

¿Ha sido útil esta solución?