Files
youlai-boot/src/main/java/com/youlai/boot/system/service/UserOnlineService.java
2026-01-03 23:05:01 +08:00

146 lines
4.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.youlai.boot.system.service;
import com.youlai.boot.platform.websocket.publisher.WebSocketPublisher;
import com.youlai.boot.platform.websocket.topic.WebSocketTopics;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* 用户在线状态服务
* 负责维护用户的在线状态和相关统计
*
* @author Ray.Hao
* @since 3.0.0
*/
@Service
@Slf4j
public class UserOnlineService {
// 在线用户映射表key为用户名value为用户在线信息
private final Map<String, UserOnlineInfo> onlineUsers = new ConcurrentHashMap<>();
private final WebSocketPublisher webSocketPublisher;
public UserOnlineService(WebSocketPublisher webSocketPublisher) {
this.webSocketPublisher = webSocketPublisher;
}
/**
* 用户上线
*
* @param username 用户名
* @param sessionId WebSocket会话ID可选
*/
public void userConnected(String username, String sessionId) {
// 生成会话ID如果未提供
String actualSessionId = sessionId != null ? sessionId : "session-" + System.nanoTime();
UserOnlineInfo info = new UserOnlineInfo(username, actualSessionId, System.currentTimeMillis());
onlineUsers.put(username, info);
log.info("用户[{}]上线,当前在线用户数:{}", username, onlineUsers.size());
// 通知在线用户状态变更
notifyOnlineUsersChange();
}
/**
* 用户下线
*
* @param username 用户名
*/
public void userDisconnected(String username) {
onlineUsers.remove(username);
log.info("用户[{}]下线,当前在线用户数:{}", username, onlineUsers.size());
// 通知在线用户状态变更
notifyOnlineUsersChange();
}
/**
* 获取在线用户列表
*
* @return 在线用户名列表
*/
public List<UserOnlineDTO> getOnlineUsers() {
return onlineUsers.values().stream()
.map(info -> new UserOnlineDTO(info.getUsername(), info.getLoginTime()))
.collect(Collectors.toList());
}
/**
* 获取在线用户数量
*
* @return 在线用户数
*/
public int getOnlineUserCount() {
return onlineUsers.size();
}
/**
* 检查用户是否在线
*
* @param username 用户名
* @return 是否在线
*/
public boolean isUserOnline(String username) {
return onlineUsers.containsKey(username);
}
/**
* 通知所有客户端在线用户变更
*/
private void notifyOnlineUsersChange() {
// 发送简化版数据(仅数量)
sendOnlineUserCount();
}
/**
* 发送在线用户数量(简化版,不包含用户详情)
*/
private void sendOnlineUserCount() {
try {
// 直接发送数量,更轻量
int count = onlineUsers.size();
webSocketPublisher.publish(WebSocketTopics.TOPIC_ONLINE_COUNT, count);
log.debug("已发送在线用户数量: {}", count);
} catch (Exception e) {
log.error("发送在线用户数量失败", e);
}
}
/**
* 用户在线信息
*/
@Data
private static class UserOnlineInfo {
private final String username;
private final String sessionId;
private final long loginTime;
}
/**
* 用户在线Dto用于返回给前端
*/
@Data
public static class UserOnlineDTO {
private final String username;
private final long loginTime;
}
/**
* 在线用户变更事件
*/
@Data
private static class OnlineUsersChangeEvent {
private String type;
private int count;
private List<UserOnlineDTO> users;
private long timestamp;
}
}