websockets mvc example java spring spring-mvc spring-websocket

java - mvc - Enviar mensaje a un usuario específico en Spring Websocket



websockets spring angular (5)

¿Cómo enviar un mensaje de websocket del servidor a un usuario específico solamente?

Mi aplicación web tiene configuración de seguridad de primavera y usa websocket. Me encuentro con un problema complicado tratando de enviar mensajes del servidor a usuarios específicos solamente .

Mi comprensión al leer el manual es del servidor que podemos hacer

simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply);

Y en el lado del cliente:

stompClient.subscribe(''/user/reply'', handler);

Pero nunca podría obtener la devolución de llamada de suscripción invocada. He intentado muchos caminos diferentes, pero no tuve suerte.

Si lo envío a / topic / reply funciona, pero todos los demás usuarios conectados también lo recibirán.

Para ilustrar el problema, he creado este pequeño proyecto en github: https://github.com/gerrytan/wsproblem

Pasos para reproducir:

1) Clona y crea el proyecto (asegúrate de estar usando jdk 1.7 y maven 3.1)

$ git clone https://github.com/gerrytan/wsproblem.git $ cd wsproblem $ mvn jetty:run

2) Navegue a http://localhost:8080 , inicie sesión usando bob / test o jim / test

3) Haga clic en "Solicitar msg específico del usuario". Esperado: aparece un mensaje "hola {nombre de usuario}" junto a "Mensaje recibido solo para mí" para este usuario, real: no se recibe nada


Ah, encontré cuál era mi problema. Primero, no registré el prefijo /user en el simple broker

<websocket:simple-broker prefix="/topic,/user" />

Entonces no necesito el prefijo extra /user al enviar:

convertAndSendToUser(principal.getName(), "/reply", reply);

Spring agregará automáticamente "/user/" + principal.getName() al destino, por lo que se convierte en "/ user / bob / reply".

Esto también significa que en javascript tuve que suscribirme a diferentes direcciones por usuario

stompClient.subscribe(''/user/'' + userName + ''/reply,...)


Creé un proyecto de websocket de muestra usando STOMP también. Lo que noto es que

@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic", "/queue");// including /user also works config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/getfeeds").withSockJS(); }

}

funciona si se incluye o no "/ user" en config.enableSimpleBroker (...


Exactamente hice lo mismo y está funcionando sin usar usuario

@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/gs-guide-websocket").withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic" , "/queue"); config.setApplicationDestinationPrefixes("/app"); } }


Mi solución está basada en la mejor explicación de Thanh Nguyen Van, pero además he configurado MessageBrokerRegistry:

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


Oh, client side no need to known about current user , el servidor lo hará por usted.

Del lado del servidor, usando la siguiente forma para enviar un mensaje a un usuario:

simpMessagingTemplate.convertAndSendToUser(username, "/queue/reply", message);

Nota: Usando queue , no topic , Spring siempre usando queue con sendToUser

Del lado del cliente

stompClient.subscribe("/user/queue/reply", handler);

Explique

Cuando cualquier conexión de websocket está abierta, Spring le asignará una session id (no HttpSession , asignar por conexión). Y cuando su cliente se suscribe a un canal, comience con /user/ , por ejemplo: /user/queue/reply , su instancia de servidor se suscribirá a una cola llamada queue/reply-user[session id]

Cuando use enviar mensaje al usuario, por ejemplo: username es admin Escribirá simpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);

Spring determinará qué session id asignó al admin usuario. Por ejemplo: encontró dos sesiones wsxedc123 y thnujm456 , Spring la traducirá a 2 destinos queue/reply-userwsxedc123 y queue/reply-userthnujm456 , y enviará su mensaje con 2 destinos a su intermediario de mensajes.

El intermediario de mensajes recibe los mensajes y los devuelve a su instancia de servidor que contiene la sesión correspondiente a cada sesión (las sesiones de WebSocket pueden ser retenidas por uno o más servidores). Spring traducirá el mensaje a destination (p. Ej .: user/queue/reply ) y la session id (p. wsxedc123 .: wsxedc123 ). Luego, envía el mensaje a la Websocket session correspondiente de Websocket session