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

WebSockets聊天系统开发中Sessions相关NullPointerException问题

问题根因与修复方案

你之前对报错的理解有误,该NullPointerException并非变量类型不匹配导致,本质是usernameSessionMap.get(传入的用户名)返回了null,也就是目标用户名在存储在线用户的Map中没有对应Session记录,直接调用getBasicRemote()方法就会触发空指针。

常见触发场景

  • 测试时仅登录了消息发送方账号,接收方账号未登录,没有对应的Session存入usernameSessionMap
  • 用户名匹配不一致:比如存入Map的用户名带有前后空格、大小写和@的用户名不符,例如存入的是Teacher,@的是teacher
  • 用户名解析逻辑存在边界漏洞:如果用户输入的私信没有带空格,例如直接发送@teachertestMessage,你的分割逻辑会把teachertestMessage当成目标用户名,自然匹配不到已存在的用户

修复方案

1. 增加空指针防御逻辑

修改sendMessageToParticularUser方法,调用前先判断目标Session是否存在,不存在时返回系统提示:

private void sendMessageToParticularUser(String username, String message) {
    System.out.println(message);
    Session targetSession = usernameSessionMap.get(username);
    // 先判断目标用户Session是否存在
    if (targetSession == null) {
        // 给发送方返回失败提示
        Session senderSession = sessionUsernameMap.entrySet().stream()
            .filter(entry -> username.equals(entry.getValue()))
            .map(Map.Entry::getKey)
            .findFirst()
            .orElse(null);
        if (senderSession != null) {
            try {
                senderSession.getBasicRemote().sendText("[系统提示] 用户" + username + "不存在或当前不在线");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        logger.info("用户{}不存在或不在线,私信发送失败", username);
        return;
    }
    try {
        targetSession.getBasicRemote().sendText(message);
    } catch (IOException e) {
        logger.info("发送私信异常: {}", e.getMessage());
        e.printStackTrace();
    }
}

2. 修复用户名解析边界问题

优化私信内容的分割逻辑,避免无空格等异常输入导致解析错误:

@OnMessage
public void onMessage(Session session, String message) throws IOException { 
    logger.info("Message Received: " + message); 
    String username = sessionUsernameMap.get(session); 
    if (message.startsWith("@")) {
        // 查找第一个空格的位置分割用户名和内容
        int firstSpaceIdx = message.indexOf(" ");
        if (firstSpaceIdx == -1) {
            // 格式错误返回提示
            sendMessageToParticularUser(username, "[系统提示] 私信格式错误,正确格式为:@用户名 消息内容");
            return;
        }
        String destUsername = message.substring(1, firstSpaceIdx).trim();
        String realMessage = message.substring(firstSpaceIdx).trim();
        sendMessageToParticularUser(destUsername, "[DM] " + username + ": " + realMessage); 
        sendMessageToParticularUser(username, "[DM] " + username + ": " + message);
    }
    else {
        broadcast(username + ": " + message);
    }
    msgRepo.save(new Message(username, message));
}

3. 验证用户上下线逻辑

在@OnOpen和@OnClose方法中增加日志,确认用户上线时是否正确存入Map,下线时是否正确移除:

@OnOpen
public void onOpen(Session session, @PathParam("username") String username) {
    sessionUsernameMap.put(session, username);
    usernameSessionMap.put(username, session);
    logger.info("用户{}上线,当前在线用户列表:{}", username, usernameSessionMap.keySet());
}

@OnClose
public void onClose(Session session) {
    String username = sessionUsernameMap.get(session);
    if (username != null) {
        sessionUsernameMap.remove(session);
        usernameSessionMap.remove(username);
        logger.info("用户{}下线,当前在线用户列表:{}", username, usernameSessionMap.keySet());
    }
}

测试时先同时登录发送方和接收方两个账号,通过日志确认两个用户都在在线列表中,再发送私信即可验证功能是否正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 14:15:06