如何使用Java EE 7 WebSockets实现对客户端的推送?

我浏览了很多Web Socket示例,演示幻灯片,它们主要集中在客户端发起客户端 – 服务器通信的相当简单的场景中。

我对另一个场景感兴趣,这似乎同样实用:纯服务器推送到客户端。

示例我想到的是一个更新网站上股票价值的应用程序。 想象一下,有一个外部系统股票交易系统,它为每个订阅的股票价值变化发送JMS消息。

我想知道如何将这样的传入JMS事件转换为服务器推送,并从Java EE 7的角度有效地和惯用地转换它。

据我所知,我应该编写一个Web套接字端点

@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方法中做任何我喜欢的@OnMessage 。 但在我的例子中,我不会从客户端收到任何消息,我会从某个外部系统获得一个事件。

有几种方法。 例如,我可以在@OnOpen方法中创建一个线程,如本博客所示 。 实际上,这种方法可能会显示出一个缺点,因为对于每个客户端,我都需要创建一个新的,可能很长的生命线程。

使用选择器的NIO通道可以做得更好,但这需要某种“手工制作”的通道管理。 可行,但相当繁琐。

另一个解决方案是ping其他系统进行更新,但同样会有点难看。 另外我也不确定@OnOpen方法是否意味着以这种方式使用。

理想情况下,传入的JMS消息会触发Web Socket推送到客户端。 任何想法如何很好地实现这样的东西?

可能这不是最优雅的方式,只是为了展示想法。 方法broadcast()将向所有连接的客户端发送消息。

 @ServerEndpoint("/echo") public class ServerEndPoint { private static Set userSessions = Collections.newSetFromMap(new ConcurrentHashMap()); @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); } } } 

我是这样做的(不需要客户端请求):

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

将活动sessionList存储在另一个类SessionManager

 List socketSessions = new ArrayList<>(); 

@OnOpen传入会话添加到列表中。 从@OnClose列表中删除会话

 @OnClose public void close(Session session) { sessionManager.removeSession(session); } 

要向所有人发送消息,

 public void broadcast(String message){ for(Session session: sessionList){ session.getBasicRemote().sendText(message); } } 

您可以在事件触发的任何位置使用sessionManager.broadcast()方法。

这是一个完整的例子,说明如何使用websocket来推动HTML5 websocket API。 https://metamug.com/article/java-push-notification-with-websocket.php

我使用omnifaces套接字组件实现了类似于您的问题的解决方案。 通知由JMS消息触发,收件人可以是特定用户或所有用户。 博客文章urlhttps://konstpan.wordpress.com/2018/03/25/push-notifications-in-a-jee-web-application-secured-by-keycloak/