che*_*1k4 0 java websocket java-ee-7
我想通过Web套接字向特定用户发送消息。到目前为止,我可以打开Web套接字并像这样从客户端读取消息:
@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());
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个独立的服务,可以在目标用户中创建消息。我的Message课是一个简单的POJO:
public class Message {
private String fromUserName;
private String toUserName;
private String content;
...
}
Run Code Online (Sandbox Code Playgroud)
当在中创建新消息时MessageService,我想通知接收者是否已连接。我想我必须添加一个方法WebSocketEndpoint.onServerMessage:
public void onServerMessage(Session session, Message message) {
session.getBasicRemote().sendText(message.getContent());
}
Run Code Online (Sandbox Code Playgroud)
但是我不知道该怎么做才行。
所有用户都将有一个ServerEndpoint实例。因此,它应该存储所有客户端会话。正如Vu.N所建议的那样,一种方法是使用地图:
Map<String, Session> sessions = new ConcurrentHashMap<>();
public void onOpen(Session session) {
String username = [...]
sessions.put(username, session);
}
Run Code Online (Sandbox Code Playgroud)
然后,很容易将消息发送给用户:
public void onServerMessage(Session session, Message message) {
sessions.get(message.getToUserName())
.getBasicRemote() // see also getAsyncRemote()
.sendText(message.getContent());
}
Run Code Online (Sandbox Code Playgroud)
现在最难的部分是获得username?
在我过去的作品中,我通过3种方式来做到这一点:
客户端连接到具有某些“密钥”的URL。此“密钥”将用于查找正确的用户名。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);
}
Run Code Online (Sandbox Code Playgroud)客户端在第一条消息中发送一些信息。您只需忽略@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);
}
Run Code Online (Sandbox Code Playgroud)可以从Cookie,JWT或其他内容中获取一些用户信息。您需要a 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"));
}
}
Run Code Online (Sandbox Code Playgroud)
然后,服务器端点将指向该配置程序:
@ServerEndpoint(value = "/example2/", configurator = CookieServerConfigurator.class)
public class WebSocketEndpoint {
Run Code Online (Sandbox Code Playgroud)
您可以获得以下信息:
@OnOpen
public void onOpen(Session session, EndpointConfig endpointConfig) {
String username = getUsername((List<String>)endpointConfig.getUserProperties().get("cookie"));
Run Code Online (Sandbox Code Playgroud)您可以在此处看到一些工作示例:https : //github.com/matruskan/websocket-example
对于更复杂的系统,您也可以使用“标记系统”,而不使用Map。然后,每个会话可以接收发送到其任何标签的消息,并且发送到标签的消息可以定向到许多会话。
| 归档时间: |
|
| 查看次数: |
7885 次 |
| 最近记录: |