2016-01-21 24 views
23

特定のセッションにメッセージを送信することはできますか?Spring WebSocket @SendToSession:特定のセッションにメッセージを送信

クライアントとSpringサーブレットの間に認証されていないwebsocketがあります。非同期ジョブが終了すると、特定の接続に非送信請求メッセージを送信する必要があります。

@Controller 
public class WebsocketTest { 


    @Autowired 
    public SimpMessageSendingOperations messagingTemplate; 

    ExecutorService executor = Executors.newSingleThreadExecutor(); 

    @MessageMapping("/start") 
    public void start(SimpMessageHeaderAccessor accessor) throws Exception { 
     String applicantId=accessor.getSessionId();   
     executor.submit(() -> { 
      //... slow job 
      jobEnd(applicantId); 
     }); 
    } 

    public void jobEnd(String sessionId){ 
     messagingTemplate.convertAndSend("/queue/jobend"); //how to send only to that session? 
    } 
} 

このコードでわかるように、クライアントは非同期ジョブを開始でき、終了すると終了メッセージが必要です。明らかに、私は応募者だけにメッセージを伝え、誰にでも放送する必要はありません。 @SendToSession注釈またはmessagingTemplate.convertAndSendToSessionメソッドを持つことは素晴らしいことです。

UPDATE

私はこの試みた:

messagingTemplate.convertAndSend("/queue/jobend", true, Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, sessionId)); 

をしかし、これはすべてのセッション、指定されたものではないだけに放送します。 convertAndSendToUserと

UPDATE 2

試験()メソッド。 このテストであり、公式の春のチュートリアルのハック:https://spring.io/guides/gs/messaging-stomp-websocket/

これは、サーバーのコードです:

@Controller 
public class WebsocketTest { 

    @PostConstruct 
    public void init(){ 
     ScheduledExecutorService statusTimerExecutor=Executors.newSingleThreadScheduledExecutor(); 
     statusTimerExecutor.scheduleAtFixedRate(new Runnable() {     
      @Override 
      public void run() { 
       messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test")); 
      } 
     }, 5000,5000, TimeUnit.MILLISECONDS); 
    } 

    @Autowired 
     public SimpMessageSendingOperations messagingTemplate; 
} 

と、これはクライアントコードです:

function connect() { 
      var socket = new WebSocket('ws://localhost:8080/hello'); 
      stompClient = Stomp.over(socket); 
      stompClient.connect({}, function(frame) { 
       setConnected(true); 
       console.log('Connected: ' + frame); 
       stompClient.subscribe('/user/queue/test', function(greeting){ 
        console.log(JSON.parse(greeting.body)); 
       }); 
      }); 
     } 

残念ながら、クライアントが受信しません5000msごとのセッションごとの応答を期待どおりにします。私は、私は、リモート・ジョブのプログレスバーを作成したいSimpMessageHeaderAccessor.getSessionId()

背景SCENARIO

でデバッグモードでそれを見るために「1」が接続されている第二のクライアントのために、有効なセッションIDであることを確信していますクライアントはサーバーに非同期ジョブを要求し、サーバーから送信されたwebsocketメッセージによって進行状況をチェックします。これはファイルのアップロードではなくリモートでの計算であるため、サーバーだけが各ジョブの進行状況を把握しています。 セッションごとにジョブが開始されるため、特定のセッションにメッセージを送信する必要があります。 クライアントはリモート計算を要求します サーバはこのジョブを開始し、すべてのジョブステップに対して、ジョブ進行状況を持つ申請者クライアントに応答します。 クライアントはジョブに関するメッセージを取得し、進行状況/ステータスバーを作成します。 これは私がセッションごとのメッセージを必要とする理由です。 私はユーザごとのメッセージを使用することもできますが、Spring は、ユーザごとにの未承諾メッセージを提供しません。(Cannot send user message with Spring Websocket

WORKING SOLUTION

__  __ ___ ___ _ __ ___ _ _ ___  ___ ___ _ _ _ _____ ___ ___ _ _ 
\ \ /// _ \ | _ \| |/ /|_ _|| \| |/__| /__|/_ \ | | | | | ||_ _||_ _|/ _ \ | \| | 
    \ \/\/ /| (_) || /| ' < | | | .` || (_ | \__ \| (_) || |__| |_| | | | | || (_) || .` | 
    \_/\_/ \___/ |_|_\|_|\_\|___||_|\_| \___| |___/ \___/ |____|\___/ |_| |___|\___/ |_|\_| 

私は最後のparamでconvertAndSendToUser方法を完了しなければならなかったアップデート2溶液(MessageHeaders)最低料金:

createHeaders()はこの方法で
messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"), createHeaders("1")); 

private MessageHeaders createHeaders(String sessionId) { 
     SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE); 
     headerAccessor.setSessionId(sessionId); 
     headerAccessor.setLeaveMutable(true); 
     return headerAccessor.getMessageHeaders(); 
    } 
+0

私はこれを見つけました:https://jira.spring.io/browse/SPR-12143 – Tobia

+0

私はあなたに例を書いています..メッセージを送信したい特定のセッションは誰にどのように伝えられますか? – Aviad

+0

これはリモートジョブ管理で、コントローラがリモートジョブ要求を受信すると、将来のジョブステータス応答をルーティングするために申請者のセッションを保存する必要があります – Tobia

答えて

18

特定の送り先を作成する必要はありませんが、既にSpring 4.1(詳細はSPR-11309を参照)のままで完了しています。ユーザーが考える

/user/queue/somethingキューをサブスクライブ、あなたが単一のセッションにメッセージを送ることができます。ユーザー名が実際にセッションIDであることから、あなたにもヘッダーとしてそれを設定しなければなりません、stated in the SimpMessageSendingOperations Javadocとして

そうDefaultUserDestinationResolverはメッセージをルーティングすることができず、メッセージをドロップします。

SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor 
    .create(SimpMessageType.MESSAGE); 
headerAccessor.setSessionId(sessionId); 
headerAccessor.setLeaveMutable(true); 

messagingTemplate.convertAndSendToUser(sessionId,"/queue/something", payload, 
    headerAccessor.getMessageHeaders()); 

あなたはこのために認証されるユーザは必要ありません。

+0

素晴らしいでしょう。明日私はそれを試してみましょう。 – Tobia

+0

これは私のためには機能しません...私はこの実行ごとに5000msのスケジューリングを試みました:messagingTemplate.convertAndSendToUser( "1"、 "/ queue/something"、payload);しかし、クライアントはメッセージを受信しません。私はそれがデバッグモードで取得するので、それは "1"セッション(2番目のクライアントconntected)であると確信しています。 – Tobia

+0

私はこのテストで私の質問にUPDATEを追加しました – Tobia

3

非常に複雑で、私の意見では、それは価値がありません。 すべてのユーザー(認証されていないユーザーも含む)のセッションIDでサブスクリプションを作成する必要があります。ユーザーはあなたが通知し、特定のセッションのためにメッセージを送信してに保存する必要がありますサブスクライブする前に、サーバー上で

stompClient.subscribe('/session/specific' + uuid, handler); 

のは、すべてのユーザーが、彼だけのためのユニークなキューに加入するとしましょうマップ:その後

@MessageMapping("/putAnonymousSession/{sessionId}") 
    public void start(@DestinationVariable sessionId) throws Exception { 
     anonymousUserSession.put(key, sessionId); 
    } 

、ユーザーにメッセージを送信したいときにする必要があります。

messagingTemplate.convertAndSend("/session/specific" + key); 

しかし、私はあなたが何をしようとしているのか、特定のセッション(匿名者)を見つける方法を本当に知っていません。

+1

これは私の実際の解決策であり、回避策のようです。 Spring WebSocketのソースを見ると、すべてのアクティブなソケットのセッションIDを得ることができ、さらに特定の接続にメッセージをルーティングするという理論的にも見えます。 Websocketで何を実現したいのかを伝えるために、シナリオのバックグラウンドで質問を更新します。 – Tobia

+0

問題はあなたが送信したい正確なセシオンが何か分からないことです。その場合、クライアントを特定のチャネルにサブスクライブする必要があります – Aviad

+0

ジョブはクライアントメッセージで開始されますので、サーバーはこのジョブを開始してアプリケーションセッションIDを保存し、このジョブが進行するとサーバーからサーバーにメッセージを送信する必要がありますジョブごとにセッションIDを保存したクライアント – Tobia

関連する問題