2017-03-15 19 views
0

Webソケットを介して特定のユーザーにメッセージを送信します。これまでのところ、Webソケットを開いてクライアントからメッセージを読むことができます。Webソケットを介して接続しているユーザーにメッセージを送信するにはどうすればよいですか?

@ServerEndpoint(value = "/wsep") 
public class WebSocketEndpoint { 

    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketEndpoint.class); 

    private Session session; 

    @OnOpen 
    public void onOpen(Session session) { 
     this.session = session; 
     try { 
      session.getBasicRemote().sendText("You are connected. Your ID is " + session.getId()); 
     } catch (Exception e) { 
      LOGGER.error("Error on open web socket", e); 
     } 
    } 

    @OnMessage 
    public void onClientMessage(String message, Session session) {  
     LOGGER.info("Message from {} is: {}", session.getId(), message); 
    } 

    @OnClose 
    public void onClose(Session session) { 
     this.session = null; 
     LOGGER.info("{} disconnected", session.getId()); 
    } 
} 

私は、ユーザ宛のメッセージを作成する独立したサービスを持っています。

public class Message { 
    private String fromUserName; 
    private String toUserName; 
    private String content; 
    ... 
} 

新しいメッセージが私のMessageServiceで作成されたとき、私は彼が接続されている場合は、受信機に知らせたい:私Messageクラスは、単純なPOJOです。私はこの方法WebSocketEndpoint.onServerMessage追加する必要が思う:

public void onServerMessage(Session session, Message message) { 
    session.getBasicRemote().sendText(message.getContent()); 
} 

をしかし、私は働くことのような何かをする方法がわかりません。

+1

実装が間違っているようです。あなたは、キーがidであるSessionを格納するために静的マップを使用するか、何かが参照/識別子である必要があります。 - クライアントが接続されている場合は、そのセッションをマップに保存します。 - クライアントが閉じられたら、そのセッションをマップから削除します。 - 新しいメッセージが作成されると、idで検索し、そのセッションを使用してメッセージを送信します。 –

答えて

1

すべてのユーザーに対して1つのServerEndpointインスタンスが存在します。したがって、すべてのクライアントセッションを保存する必要があります。

Map<String, Session> sessions = new ConcurrentHashMap<>(); 

public void onOpen(Session session) { 
    String username = [...] 
    sessions.put(username, session); 
} 

を次に、ユーザーにメッセージを送信することが容易になります:Vu.Nは、あなたがそれを行うことができます一つの方法は、マップを使用している、示唆したように

public void onServerMessage(Session session, Message message) { 
    sessions.get(message.getToUserName()) 
      .getBasicRemote() // see also getAsyncRemote() 
      .sendText(message.getContent()); 
} 

今、最も難しい部分がありますusernameを取得しますか?私の過去の作品で

、私は3通りの方法でそれをやった:

  1. クライアントはいくつかの「キー」を持っているURLに接続します。この「キー」は正しいユーザー名を見つけるために使用されます。 WebSocketのサーバーエンドポイントは次のようになります:

    @ServerEndpoint(value="/wsep/{key}") // the URL will have an extra "key" 
    public class WebSocketEndpoint { 
    [...] 
    @OnOpen 
    public void onOpen(Session session, @PathParam("key") String key) { 
        String username = getUserNameWithKey(key); 
        sessions.add(username, session); 
    } 
    
  2. クライアントは、最初のメッセージにいくつかの情報を送信します。あなただけの@OnOpen部分を無視:

    @OnOpen 
    public void onOpen(Session session) { 
        LOGGER.info("Session open. ID: {}", session.getId()); 
    } 
    
    @OnMessage 
    public void onMessage(Session session, String message) { 
        String username = getUserNameFromMessage(message); 
        sessions.add(username, session); 
    } 
    
  3. 一部のユーザー情報は、クッキー、JWT、もしくは何かから入手することができます。リクエストからその情報を取得するには、ServerEndpointConfig.Configuratorが必要です。たとえば:

    @ServerEndpoint(value = "/example2/", configurator = CookieServerConfigurator.class) 
    public class WebSocketEndpoint { 
    

    を、あなたは、このような情報を得ることができます:

    public class CookieServerConfigurator extends ServerEndpointConfig.Configurator { 
    
        @Override 
        public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { 
         Map<String,List<String>> headers = request.getHeaders(); 
         sec.getUserProperties().put("cookie", headers.get("cookie")); 
        } 
    } 
    

    そして、サーバエンドポイントは、そのコンフィギュレータを指すようになりますあなたが見ることができます

    @OnOpen 
    public void onOpen(Session session, EndpointConfig endpointConfig) { 
        String username = getUsername((List<String>)endpointConfig.getUserProperties().get("cookie")); 
    

いくつかの実例がここにあります:https://github.com/matruskan/websocket-example

さらに複雑なシステムでは、マップを使用する代わりに、「タギングシステム」を使用することもできます。その後、各セッションはそのタグのいずれかに送信されたメッセージを受信でき、タグに送信されたメッセージは多くのセッションに送信されます。

+0

ServerEndpointConfig [here](https://stackoverflow.com/questions/17936440/accessing-httpsession-from-httpservletrequest-in-a-web-socket-serverendpoint?rq=1)に関する素晴らしい答えがあります。 – Matruskan

関連する問題