基于Listener类统计活跃用户数的技术求助
实现活跃用户数统计的解决方案
当然可以!只需要在现有代码基础上做几个小改动就能实现,核心思路是跟踪用户的唯一标识(而非会话ID),同时处理同一用户多会话的场景——只要该用户还有至少一个活跃会话,就仍算作活跃用户。
核心改动说明
现有代码统计的是会话ID,所以同一用户多登录会重复计数。我们需要:
- 用线程安全的集合跟踪每个用户的活跃会话数量
- 维护一个自动去重的活跃用户集合,只有当用户所有会话都销毁时才移除该用户
修改后的完整代码
import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class SessionCounter implements HttpSessionListener { // 记录每个用户的活跃会话数,线程安全 private Map<String, Integer> userSessionCount = new ConcurrentHashMap<>(); // 存储当前活跃用户的唯一标识(自动去重) private Set<String> activeUsers = ConcurrentHashMap.newKeySet(); public SessionCounter() { } @Override public void sessionCreated(HttpSessionEvent event) { HttpSession session = event.getSession(); // 从会话中获取用户唯一标识(需在登录成功后存入Session) String userId = (String) session.getAttribute("userId"); if (userId != null) { // 原子性更新用户会话数:首次登录则设为1,否则加1 userSessionCount.compute(userId, (key, currentCount) -> currentCount == null ? 1 : currentCount + 1); // 将用户加入活跃集合(重复添加不影响) activeUsers.add(userId); } session.setAttribute("counter", this); } @Override public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); String userId = (String) session.getAttribute("userId"); if (userId != null) { // 原子性减少用户会话数 userSessionCount.compute(userId, (key, currentCount) -> currentCount == null ? 0 : currentCount - 1); // 当用户所有会话都销毁时,移除出活跃用户集合 if (userSessionCount.get(userId) <= 0) { userSessionCount.remove(userId); activeUsers.remove(userId); } } session.setAttribute("counter", this); } // 新增:获取活跃用户数 public int getActiveUserNumber() { return activeUsers.size(); } // 保留原有的活跃会话数统计方法(如果需要) public int getActiveSessionNumber() { int total = 0; for (int count : userSessionCount.values()) { total += count; } return total; } }
必须配合的登录逻辑
在用户登录验证成功后,务必将用户的唯一标识(比如用户ID、用户名)存入Session,示例代码如下:
// 登录成功后的处理 String userId = "从数据库获取的用户唯一ID"; request.getSession().setAttribute("userId", userId);
关键注意点
- 使用
ConcurrentHashMap和ConcurrentHashMap.newKeySet()是为了保证多线程环境下的安全性,避免并发修改问题 - 如果你的用户唯一标识不是字符串类型,只需将代码中的
String替换为对应类型即可 - 若用户未登录就创建了会话(比如访问首页),这段代码会自动忽略,不会计入活跃用户
内容的提问来源于stack exchange,提问作者Abhinandan prasad
相关产品推荐
相关产品推荐

