2017-03-15 20 views
0

我想通過網絡套接字發送消息給特定用戶。到目前爲止,我可以從客戶端打開一個網頁插座和閱讀的消息像:如何通過網絡套接字將消息發送給已連接的用戶?

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

我有目的地到用戶創建消息的獨立服務。我Message類是一個簡單的POJO:

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

當我MessageService創建一個新的消息,我想,如果他被連接到通知接收機。我想我要補充的方法WebSocketEndpoint.onServerMessage

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

但我不知道該怎麼做這樣的事情,其工作原理。

+1

似乎你的實現是錯誤的。你應該使用一個靜態映射來存儲Session,key是id或者可以是引用/標識符。 - 連接客戶端時,將其會話存儲到地圖。 - 客戶關閉時,從地圖中刪除其會話。 - 創建新消息時,按ID查找並使用該會話發送消息。 –

回答

1

將爲您的所有用戶提供一個ServerEndpoint實例。所以,它應該存儲所有的客戶端會話。作爲Vu.N建議,一個方法可以做到這一點是使用地圖:

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

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

然後,它會很容易將消息發送給用戶:

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. 一些用戶信息可以從cookie中,智威湯遜,或者說獲得。您需要一個ServerEndpointConfig.Configurator以從請求中獲取該信息。例如:

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

    然後,服務器端點將指向配置:

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

    ,你可以得到這樣的信息:

    @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 [這裏]有一個很好的答案(https://stackoverflow.com/questions/17936440/accessing-httpsession-from-httpservletrequest-in-a-web-socket-serverendpoint?rq=1) – Matruskan

相關問題