113 lines
3.2 KiB
Java
113 lines
3.2 KiB
Java
|
|
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<String> 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<String, Object> getStats() {
|
|||
|
|
checkAndResetIfNewDay();
|
|||
|
|
Map<String, Object> stats = new ConcurrentHashMap<>();
|
|||
|
|
stats.put("todayVisitors", todayVisitors.size());
|
|||
|
|
stats.put("date", currentDate.toString());
|
|||
|
|
stats.put("uptime", getUptime());
|
|||
|
|
return stats;
|
|||
|
|
}
|
|||
|
|
}
|