上一篇讲了 WebSocket 的基础,这篇实现一个完整的聊天室——在线用户管理、群聊、私聊。
一、在线用户管理
@Component
public class UserSessionManager {
private final Map<Long, String> onlineUsers = new ConcurrentHashMap<>();
private final Map<String, Long> sessionUsers = new ConcurrentHashMap<>();
public void online(Long userId, String sessionId) {
onlineUsers.put(userId, sessionId);
sessionUsers.put(sessionId, userId);
}
public void offline(String sessionId) {
Long userId = sessionUsers.remove(sessionId);
if (userId != null) {
onlineUsers.remove(userId);
}
}
public int onlineCount() {
return onlineUsers.size();
}
public List<Long> allUserIds() {
return new ArrayList<>(onlineUsers.keySet());
}
public boolean isOnline(Long userId) {
return onlineUsers.containsKey(userId);
}
}
二、WebSocket 处理器
@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {
private final UserSessionManager sessionManager;
private final SimpMessagingTemplate messagingTemplate;
@Autowired
public ChatWebSocketHandler(UserSessionManager sm, SimpMessagingTemplate mt) {
this.sessionManager = sm;
this.messagingTemplate = mt;
}
@Override
public void afterConnectionEstablished(WebSocketSession session) {
Long userId = getUserIdFromSession(session);
sessionManager.online(userId, session.getId());
broadcast("系统", userId + " 上线了,当前在线 " + sessionManager.onlineCount() + " 人");
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
Long userId = getUserIdFromSession(session);
String payload = message.getPayload();
ChatMessage msg = JSON.parseObject(payload, ChatMessage.class);
if (msg.getToUserId() == null) {
// 群聊:广播给所有在线用户
messagingTemplate.convertAndSend("/topic/chat",
Map.of("from", userId, "content", msg.getContent()));
} else {
// 私聊:只发给指定用户
messagingTemplate.convertAndSendToUser(
msg.getToUserId().toString(), "/queue/chat",
Map.of("from", userId, "content", msg.getContent()));
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
Long userId = getUserIdFromSession(session);
sessionManager.offline(session.getId());
broadcast("系统", userId + " 下线了");
}
}
三、前端聊天界面
<script>
// 连接
var socket = new WebSocket('ws://localhost:9090/chat');
socket.onopen = function() {
console.log('连接成功');
};
// 接收消息
socket.onmessage = function(event) {
var msg = JSON.parse(event.data);
addMessage(msg);
};
// 发送群聊
function sendGroup() {
socket.send(JSON.stringify({
content: document.getElementById('input').value
}));
}
// 发送私聊
function sendPrivate(toUserId) {
socket.send(JSON.stringify({
toUserId: toUserId,
content: document.getElementById('input').value
}));
}
</script>
四、在线人数统计
@RestController
@RequestMapping("/api/chat")
public class ChatController {
@Autowired
private UserSessionManager sessionManager;
@GetMapping("/online-count")
public ResultVO<Integer> onlineCount() {
return ResultVO.success(sessionManager.onlineCount());
}
}
💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/MySQL 实战干货,不让你白来。

6124

被折叠的 条评论
为什么被折叠?



