messagemapping example baeldung java spring spring-security spring-websocket spring-messaging

java - baeldung - spring boot websocket server example



Spring Websockets @SendToUser sin inicio de sesiĆ³n? (3)

Creo que una solución podría ser evitar usar @SendToUser y usar SimpMessagingTemplate sin SimpMessagingTemplate y enviar mensajes a un destino que controle para las sesiones abiertas.

Por ej. suponiendo que tenía alguna identidad para una nueva sesión de websocket, puede suscribirse a una cola con ese identificador en el nombre de la cola:

stomp.subscribe("/queue/chats" + "-" + mycustomidentifier, onmessage);

Ahora, en el lado del oyente del websocket de Spring, puede dirigir sus respuestas usando SimpMessagingTemplate :

@Controller public class MyController { @Autowired private SimpMessagingTemplate simpMessagingTemplate; @MessageMapping("/chats") public void handleChat(@Payload ChatMessage message) { this.simpMessagingTemplate.convertAndSend("/queue/chats-" + "mycustomidentifier", "[" + getTimestamp() + "]:" + message.getMessage()); } ....

Tengo una aplicación simple de primavera con funcionalidad websocket y todo funciona hasta ahora. Ahora quiero enviar un mensaje de mi servidor a un cliente específico usando la anotación @SendToUser. Esto me da el error "Ignorando mensaje, no hay información principal disponible". Entiendo que no tengo ningún inicio de sesión en mi servidor, por lo que cada usuario es "anónimo" y no tiene un principal (no estoy usando la seguridad de primavera por el momento). Pero cada usuario tiene una identificación de sesión. ¿No es posible utilizar la identificación de sesión de alguna manera para diferenciar entre usuarios? ¿Cómo puedo lograr eso para que mis usuarios obtengan un principal que corresponde a la id de la sesión?


Use @SendToUser y agregue "/ user /" al frente de la cola cuando se suscriba (solo del lado del suscriptor). El resto funciona magia :-)

En lugar de

Java Server: @SendTo("/topic/showResult")

y

JS Client: stompClient.subscribe(''/topic/showResult'', function(calResult){ ....

utilizar:

Java Server: @SentToUser("/topic/showResult")

y

JS Client: stompClient.subscribe(''/user/topic/showResult'', function(calResult){ ....


Basándome en la respuesta de Biju y usando la identificación de sesión generada por Stomp (gracias, mariusz2108 en su respuesta a una pregunta similar ), esto es lo que funcionó para mí (basado en el ejemplo canónico de Spring )

Cliente SpringFramework:

private SimpMessagingTemplate template; @Autowired public GreetingController(SimpMessagingTemplate template) { this.template = template; } @MessageMapping("/hello") public void greeting(HelloMessage message, @Header("simpSessionId") String sessionId) throws Exception { template.convertAndSend("/queue/greeting-"+sessionId, new Greeting("Hello, " + message.getName())); }

Cliente de JavaScript:

function connect() { var socket = new SockJS(''/gs-guide-websocket''); stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { var sessionId = ///([^//]+)//websocket/.exec(socket._transport.url)[1]; console.log("connected, session id: " + sessionId); stompClient.subscribe(''/queue/greeting-''+sessionId, function (greeting) { showGreeting(JSON.parse(greeting.body).content); }); }); }

En lugar de la ID de la sesión de Stomp, puede usar la ID de sesión de su contenedor web (por ejemplo, JSESSIONID), pero ahora esa cookie no está accesible de forma predeterminada desde JavaScript (para Tomcat), esta es una perspectiva más difícil.