我浏览了很多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
方法中做任何我喜欢的事情。但在我的例子中,我不会从客户端收到任何消息,我会从某个外部系统获得一个事件。
有几种方法。例如,我可以使用@OnOpen
方法创建一个帖子,如this blog中所示。实际上,这种方法可能会显示出一个缺点,因为对于每个客户端,我都需要创建一个新的,可能很长的生命线程。
使用带有选择器的NIO通道可以做得更好,但这需要某种类型的手工制作"渠道管理。可行,但相当繁琐。
另一种解决方案是ping一些其他系统进行更新,但同样会有点难看。此外,我也不确定是否应该以这种方式使用@OnOpen
方法。
理想情况下,传入的JMS消息会触发Web Socket推送到客户端。任何想法如何很好地实现这样的东西?
答案 0 :(得分: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);
}
}
}
答案 1 :(得分: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());
}
}
}
答案 2 :(得分:1)
将活动sessionList
存储在另一个类SessionManager
中。
List<Session> 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()
方法。
这是如何使用HTML5 websocket API使用websocket进行推送的完整示例。 https://metamug.com/article/java-push-notification-with-websocket.php
答案 3 :(得分:-3)
我使用omnifaces套接字组件实现了类似于您的问题的解决方案。通知由JMS消息触发,收件人可以是特定用户或所有用户。博客文章网址https://konstpan.wordpress.com/2018/03/25/push-notifications-in-a-jee-web-application-secured-by-keycloak/