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
相关产品推荐
相关产品推荐

