You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java WebSocket能否向指定session发送消息及实现方案

实现方案

这个需求完全可以实现,基于你现有代码仅需做少量修改即可,步骤如下:

1. 调整存储结构

首先新增一个用户名到对应Endpoint实例的映射,方便直接通过目标用户名定位到需要发送的会话,同时替换原有HashMap为线程安全的ConcurrentHashMap避免并发问题:

// 替换原来的users HashMap
private static final Map<String, String> sessionIdToUsername = new ConcurrentHashMap<>();
// 新增用户名到Endpoint的映射
private static final Map<String, ChatEndpoint> usernameToEndpoint = new ConcurrentHashMap<>();

2. 调整@OnOpen逻辑

新增的映射在连接建立时写入数据:

@OnOpen
public void onOpen(Session session, @PathParam("username") String username) throws IOException, EncodeException {
    this.session = session;
    chatEndpoints.add(this);
    // 两个映射都赋值
    sessionIdToUsername.put(session.getId(), username);
    usernameToEndpoint.put(username, this);
    
    Message message = new Message();
    message.setFrom(username);
    message.setContent("Connected!");
    broadcast(message);
}

3. 新增单播发送方法

单独封装向指定用户发送消息的逻辑,需要你保证Message类已经新增to字段及对应的get/set方法:

private static void sendToUser(Message message) throws IOException, EncodeException {
    String targetUsername = message.getTo();
    ChatEndpoint targetEndpoint = usernameToEndpoint.get(targetUsername);
    if (targetEndpoint != null) {
        synchronized (targetEndpoint) {
            targetEndpoint.session.getBasicRemote().sendObject(message);
        }
    }
    // 可自行补充目标用户不存在时的异常处理逻辑,比如给发送方返回提示
}

4. 调整@OnMessage逻辑

根据消息是否指定接收人判断走广播还是单播:

@OnMessage
public void onMessage(Session session, Message message) throws IOException, EncodeException {
    String fromUsername = sessionIdToUsername.get(session.getId());
    message.setFrom(fromUsername);
    // 判断是否有指定接收人
    if (message.getTo() != null && !message.getTo().trim().isEmpty()) {
        sendToUser(message);
    } else {
        broadcast(message);
    }
    System.out.println(message.getContent());
}

可选:按sessionId发送的实现

如果你不需要按用户名发送,直接按sessionId发送,可以不用新增usernameToEndpoint映射,直接在单播方法里遍历匹配sessionId即可:

private static void sendToSession(Message message) throws IOException, EncodeException {
    String targetSessionId = message.getTo();
    chatEndpoints.forEach(endpoint -> {
        if (endpoint.session.getId().equals(targetSessionId)) {
            synchronized (endpoint) {
                try {
                    endpoint.session.getBasicRemote().sendObject(message);
                } catch (IOException | EncodeException e) {
                    e.printStackTrace();
                }
            }
        }
    });
}

补充连接关闭逻辑

记得新增@OnClose方法,连接关闭时清理对应映射数据避免内存泄漏:

@OnClose
public void onClose(Session session) {
    chatEndpoints.remove(this);
    String username = sessionIdToUsername.remove(session.getId());
    if (username != null) {
        usernameToEndpoint.remove(username);
    }
}

内容的提问来源于stack exchange,提问作者coco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 05:24:05