How to send a message through web socket to a connected user?

ぐ巨炮叔叔 提交于 2021-02-08 10:13:03

问题


I want to send a message through a web socket to a specific user. So far I can open a web socket and read message from client like that:

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

I have an independent service which creates message in destination to a user. My Message class is a simple POJO:

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

When a new message is created in my MessageService, I want to inform the receiver if he is connected. I think I have to add a method WebSocketEndpoint.onServerMessage:

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

But I don't know how to do something like that which works.


回答1:


There will be one instance of the ServerEndpoint for all your users. So, it should store all client sessions. As Vu.N suggested, one way you can do it is using a map:

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

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

Then, it will be easy to send the message to the user:

public void onServerMessage(Session session, Message message) {
    sessions.get(message.getToUserName())
            .getBasicRemote() // see also getAsyncRemote()
            .sendText(message.getContent());
}

Now the hardest part is to get the username?

In my past works, I've done it in 3 ways:

  1. The client connects to a URL that has some "key". This "key" would be used to find the right username. The WebSocket server endpoint would be like this:

    @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. The client sends some information in the first message. You just ignore the @OnOpen part:

    @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. Some user info can be obtained from a cookie, JWT, or something. You'll need a ServerEndpointConfig.Configurator to get that information from the request. For example:

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

    Then, the server endpoint will point to that configurator:

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

    and you can get the information like this:

    @OnOpen
    public void onOpen(Session session, EndpointConfig endpointConfig) {
        String username = getUsername((List<String>)endpointConfig.getUserProperties().get("cookie"));
    

You can see some working examples here: https://github.com/matruskan/websocket-example

For more complex systems, you can also have a "tagging system", instead of using a Map. Then, each session can receive messages sent to any of its tags, and a message sent to a tag can be directed to many sessions.



来源:https://stackoverflow.com/questions/42804923/how-to-send-a-message-through-web-socket-to-a-connected-user

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