我想通过网络套接字向特定用户发送消息。到目前为止,我可以打开一个网络套接字并从客户端读取消息,如下所示:
@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());
}
}
我有一个独立的服务,可以在目的地向用户创建消息。我的 Message
类是一个简单的 POJO:
public class Message {
private String fromUserName;
private String toUserName;
private String content;
...
}
当我的 MessageService
中创建一条新消息时,我想通知接收者是否已连接。我想我必须添加一个方法 WebSocketEndpoint.onServerMessage
:
public void onServerMessage(Session session, Message message) {
session.getBasicRemote().sendText(message.getContent());
}
但我不知道如何做类似的事情。
最佳答案
您的所有用户都将拥有一个 ServerEndpoint 实例。因此,它应该存储所有客户端 session 。正如 Vu.N 所建议的,一种方法是使用 map :
Map<String, Session> sessions = new ConcurrentHashMap<>();
public void onOpen(Session session) {
String username = [...]
sessions.put(username, session);
}
然后,向用户发送消息就很容易了:
public void onServerMessage(Session session, Message message) {
sessions.get(message.getToUserName())
.getBasicRemote() // see also getAsyncRemote()
.sendText(message.getContent());
}
现在最难的部分是获取用户名
?
在我过去的作品中,我通过三种方式做到了这一点:
客户端连接到具有某些“ key ”的 URL。该“ key ”将用于查找正确的用户名。 WebSocket 服务器端点将如下所示:
@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); }
客户端在第一条消息中发送一些信息。你只需忽略@OnOpen部分:
@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); }
一些用户信息可以从 cookie、JWT 等获取。您需要一个
ServerEndpointConfig.Configurator
来从请求中获取该信息。例如: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")); } }
然后,服务器端点将指向该配置器:
@ServerEndpoint(value = "/example2/", configurator = CookieServerConfigurator.class) public class WebSocketEndpoint {
你可以得到这样的信息:
@OnOpen public void onOpen(Session session, EndpointConfig endpointConfig) { String username = getUsername((List<String>)endpointConfig.getUserProperties().get("cookie"));
您可以在此处查看一些工作示例:https://github.com/matruskan/websocket-example
对于更复杂的系统,您还可以拥有“标记系统”,而不是使用 map 。然后,每个 session 都可以接收发送到其任何标签的消息,并且发送到标签的消息可以定向到多个 session 。
关于java - 如何通过 Web 套接字向连接的用户发送消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42804923/