package com.example.demo.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * 在线统计服务 * 通过IP地址统计当天访问的独立用户数 */ @Service public class OnlineStatsService { private static final Logger logger = LoggerFactory.getLogger(OnlineStatsService.class); // 存储当天访问过的IP地址(使用Set去重) private final Set todayVisitors = ConcurrentHashMap.newKeySet(); // 记录当前日期,用于判断是否需要重置 private volatile LocalDate currentDate = LocalDate.now(); // 系统启动时间 private final LocalDateTime startTime = LocalDateTime.now(); /** * 记录访问IP * @param ip 访问者IP地址 */ public void recordVisit(String ip) { if (ip == null || ip.isEmpty()) { return; } // 检查是否需要重置(新的一天) checkAndResetIfNewDay(); // 添加IP到今日访客列表 todayVisitors.add(ip); } /** * 获取当天在线人数(独立IP数) * @return 当天访问的独立IP数量 */ public int getTodayVisitorCount() { checkAndResetIfNewDay(); return todayVisitors.size(); } /** * 检查是否是新的一天,如果是则重置统计 */ private void checkAndResetIfNewDay() { LocalDate today = LocalDate.now(); if (!today.equals(currentDate)) { synchronized (this) { if (!today.equals(currentDate)) { logger.info("新的一天开始,重置在线统计。昨日访客数: {}", todayVisitors.size()); todayVisitors.clear(); currentDate = today; } } } } /** * 每天凌晨0点重置统计 */ @Scheduled(cron = "0 0 0 * * ?") public void resetDailyStats() { logger.info("定时任务:重置每日在线统计。昨日访客数: {}", todayVisitors.size()); todayVisitors.clear(); currentDate = LocalDate.now(); } /** * 获取系统运行时间(格式化为 X小时X分) * @return 运行时间字符串 */ public String getUptime() { Duration duration = Duration.between(startTime, LocalDateTime.now()); long hours = duration.toHours(); long minutes = duration.toMinutes() % 60; if (hours > 0) { return hours + "小时" + minutes + "分"; } else { return minutes + "分钟"; } } /** * 获取统计信息 * @return 包含统计数据的Map */ public Map getStats() { checkAndResetIfNewDay(); Map stats = new ConcurrentHashMap<>(); stats.put("todayVisitors", todayVisitors.size()); stats.put("date", currentDate.toString()); stats.put("uptime", getUptime()); return stats; } }