You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Listener类统计活跃用户数的技术求助

实现活跃用户数统计的解决方案

当然可以!只需要在现有代码基础上做几个小改动就能实现,核心思路是跟踪用户的唯一标识(而非会话ID),同时处理同一用户多会话的场景——只要该用户还有至少一个活跃会话,就仍算作活跃用户。

核心改动说明

现有代码统计的是会话ID,所以同一用户多登录会重复计数。我们需要:

  1. 用线程安全的集合跟踪每个用户的活跃会话数量
  2. 维护一个自动去重的活跃用户集合,只有当用户所有会话都销毁时才移除该用户

修改后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:05:40