How to implement push to client using Java EE 7 WebSockets?

 ̄綄美尐妖づ 提交于 2019-12-18 13:09:27

问题


I've browsed a lot of Web Socket examples, presentation slides and they are mostly concentrated on a rather simple scenarios in which client-server communication is initiated by the client.

I am interested in another scenario, which seems to be equally practical: pure server push to client.

Example I have in mind is an application that updates stocks value on a website. Imagine there is an external system stock exchange system, which is sending a JMS message for every subscribed stock value change.

I would like to know how to translate such incoming JMS event into a server push and to it efficiently and idiomatically from a Java EE 7 point of view.

As far as I can understand the spec, I am supposed to write a web socket endpoint

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

Everything is easy when I am getting a message from the frontend, I can do whatever I like in the @OnMessage method. But in my example I will not get any message from the client, I'll get an event from some external system.

There are a few approaches. For instance I can create a thread in an @OnOpen method, as demonstrated in this blog. In practice that approach might show a shortcoming since for every client I would need to create a new, potentially long living thread.

One can do better using NIO channels with selectors, but this would demand some kind of "hand made" channels management. Doable, but rather cumbersome.

Another solution would be to ping some other system for updates, but again it would be kind of ugly. In addition I am also not sure if an @OnOpen method is meant to be used in that way.

Ideally an incoming JMS message would trigger a Web Socket push to the client. Any ideas how to implement something like this nicely?


回答1:


Probably this is not most elegant way but just to demonstrate idea. Method broadcast() will send message to all connected clients.

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

}



回答2:


I do it this way (no client request is needed):

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



回答3:


Store the active sessionList in another class SessionManager.

List<Session> socketSessions = new ArrayList<>();

Add incoming session in @OnOpen to list. Remove session from list in @OnClose

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

To send a message to everyone,

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

You can use the sessionManager.broadcast() method wherever the event triggers.

Here is a complete example of how websocket can be used to make push with HTML5 websocket API. https://metamug.com/article/java-push-notification-with-websocket.php




回答4:


I have implemented a solution similar to your problem using omnifaces socket component. Notifications are triggered by JMS messages and recipients may be specific users or all of them. The blog post url https://konstpan.wordpress.com/2018/03/25/push-notifications-in-a-jee-web-application-secured-by-keycloak/



来源:https://stackoverflow.com/questions/26409937/how-to-implement-push-to-client-using-java-ee-7-websockets

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!