Invio di messaggi a un utente specifico su Spring Websocket

Come inviare un messaggio WebSocket dal server solo a un utente specifico?

La mia webapp ha una configurazione di sicurezza primaverile e utilizza websocket. Sto incontrando problemi complessi cercando di inviare messaggi dal server solo a un utente specifico .

La mia comprensione dalla lettura del manuale proviene dal server che possiamo fare

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

E sul lato client:

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

Ma non ho mai potuto richiamare la richiamata della sottoscrizione. Ho provato molti percorsi diversi ma senza fortuna.

    Se lo invio a / topic / reply funziona, ma anche tutti gli altri utenti connessi lo riceveranno.

    Per illustrare il problema ho creato questo piccolo progetto su github: https://github.com/gerrytan/wsproblem

    Passi per riprodurre:

    1) Clona e crea il progetto (assicurati di utilizzare jdk 1.7 e maven 3.1)

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

    2) Passare a http://localhost:8080 , accedere utilizzando bob / test o jim / test

    3) Fare clic su “Richiedi msg specifico dell’utente”. Previsto: un messaggio “ciao {nome utente}” viene visualizzato accanto a “Solo messaggio ricevuto per me” solo per questo utente, Effettivo: non viene ricevuto nulla

    Oh, client side no need to known about current user , il server lo farà per te.

    Sul lato server, utilizzando il seguente modo per inviare un messaggio a un utente:

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

    Nota: utilizzando la queue , non l’ topic , Spring utilizza sempre la queue con sendToUser

    Dal lato del cliente

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

    Spiegare

    Quando viene aperta una qualsiasi connessione WebSocket, Spring assegna un session id (non HttpSession , assegnato per connessione). E quando il tuo cliente si iscrive a un canale inizia con /user/ , ad esempio: /user/queue/reply , l’istanza del server si abbonerà a una coda chiamata queue/reply-user[session id]

    Quando usi invia un messaggio all’utente, ad esempio: username è admin Scriverete simpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);

    Spring determinerà quale session id mappato all’amministratore dell’utente. Ad es .: Ha trovato due sessioni wsxedc123 e thnujm456 , Spring la tradurrà in 2 queue/reply-userwsxedc123 destinazione queue/reply-userwsxedc123 e in queue/reply-userthnujm456 , e invierà il tuo messaggio con 2 destinazioni al tuo broker di messaggi.

    Il broker dei messaggi riceve i messaggi e li restituisce all’istanza del server che tiene la sessione corrispondente a ciascuna sessione (le sessioni WebSocket possono essere conservate da uno o più server). Spring tradurrà il messaggio a destination (es .: user/queue/reply ) e session id (es .: wsxedc123 ). Quindi, invia il messaggio alla Websocket session corrispondente

    Ah ho trovato qual era il mio problema. Per prima cosa non ho registrato il prefisso /user sul broker semplice

      

    Quindi non ho bisogno del prefisso extra /user quando invio:

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

    Spring aggiungerà automaticamente "/user/" + principal.getName() alla destinazione, quindi si risolverà in “/ user / bob / reply”.

    Ciò significa anche in javascript che dovevo iscriversi a diversi indirizzi per utente

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

    La mia soluzione è basata sulla migliore spiegazione di Thanh Nguyen Van, ma in aggiunta ho configurato MessageBrokerRegistry:

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

    Ho creato anche un progetto websocket di esempio con STOMP. Quello che sto notando è quello

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

    }

    funziona anche se “/ user” è incluso in config.enableSimpleBroker (…

    Esattamente ho fatto lo stesso e funziona senza usare l’utente

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