SpringBoot 整合 WebSocket 进阶——在线用户、群聊、私聊

上一篇讲了 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 实战干货,不让你白来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值