2014-10-16 42 views
9

我瀏覽過很多Web Socket示例,演示文稿幻燈片,它們大多集中在客戶端發起客戶端 - 服務器通信的相當簡單的場景中。如何使用Java EE 7 WebSocket實現推送到客戶端?

我對另一種場景感興趣,它似乎同樣實用:純服務器推送到客戶端。

示例我記住的是一個應用程序,它可以更新網站上的股票價值。假設有一個外部系統證券交易所繫統,它爲每個訂閱的股票價值變化發送JMS消息。

我想知道如何將這種傳入的JMS事件轉換爲服務器推送,並從Java EE 7的角度高效地慣用它。

至於我能理解需求,我應該寫一個網絡套接字端點

@ServerEndpoint("/demo") 
public class WSEndpoint { 
    private static final Logger LOG = Logger.getLogger(WSEndpoint.class); 

    @OnMessage 
    public void onMessage(String message, Session session) { 
    LOG.info("Received : " + message + ", session:" + session.getId()); 
    } 

    @OnOpen 
    public void open(Session session) { 
    LOG.info("Open session:" + session.getId());   
    } 

    @OnClose 
    public void close(Session session, CloseReason c) { 
    log.info("Close session:" + session.getId()); 
    } 
} 

一切都很簡單,當我從前臺得到一個消息,我可以做任何我喜歡的@OnMessage方法。但在我的例子中,我不會從客戶端收到任何消息,我會從外部系統獲取事件。

有幾種方法。例如,我可以在@OnOpen方法中創建一個線程,如this blog中所示。在實踐中,這種方法可能會顯示出一個缺點,因爲對於每個客戶我都需要創建一個新的,可能長的生活線程。

使用帶選擇器的NIO通道可以做得更好,但這需要某種「手工製造」通道管理。可行,但相當麻煩。

另一個解決方案是ping一些其他系統的更新,但它又會有點醜。另外,我也不確定是否應該以這種方式使用@OnOpen方法。

理想情況下,傳入的JMS消息將觸發Web套接字推送到客戶端。任何想法如何很好地實現這樣的東西?

+1

https://blogs.oracle.com/brunoborges/entry/integrating_websockets_and_jms_with – 2014-10-17 07:48:24

+0

感謝您的鏈接。這看起來相當不錯(第7點有實際的推送實施)。這是通過以下方式完成的:我們必須創建一組所有會話(靜態同步集)。然後,如果我們想發送推送給客戶端,我們會通過該設置並觸發推送。這種方法有一些缺點,但沒有什麼是無法克服的。 – 2014-10-17 08:14:23

+0

我們的問題是強烈關聯的:https://stackoverflow.com/questions/27037570/find-websocket-session-by-id-in-java-ee-7/27045235 – Ihromant 2014-11-21 18:09:10

回答

4

也許這不是最優雅的方式,而只是爲了展示想法。方法broadcast()將發送消息給所有連接的客戶端。

@ServerEndpoint("/echo") 
public class ServerEndPoint { 

    private static Set<Session> userSessions = Collections.newSetFromMap(new ConcurrentHashMap<Session, Boolean>()); 

    @OnOpen 
    public void onOpen(Session userSession) { 
     userSessions.add(userSession); 
    } 

    @OnClose 
    public void onClose(Session userSession) { 
     userSessions.remove(userSession); 
    } 

    @OnMessage 
    public void onMessage(String message, Session userSession) { 
     broadcast(message); 
    } 

    public static void broadcast(String msg) { 
     for (Session session : userSessions) { 
      session.getAsyncRemote().sendText(msg); 
     } 
    } 

} 
+0

使用getAsyncRemote()或getBasicRemote()方法更好嗎? – 2017-05-02 21:27:23

1

我做這種方式(不需要客戶端的請求):

@ServerEndpoint("/hello") 
public class HelloWebSocket { 

    @OnOpen 
    public void greetTheClient(Session session){ 
     try { 
     session.getBasicRemote().sendText("Hello stranger"); 

    } catch (IOException ioe) { 
     System.out.println(ioe.getMessage()); 
    } 
    } 
}