Files
FrameTour-BE/src/main/java/com/ycwl/basic/task/ScenicStatsTask.java
Jerry Yan 631d5c175f feat(payment): 支付与退款后清除景区统计缓存
- 在支付成功、取消、退款回调后增加缓存删除逻辑
- 新增 `invalidateStatisticsCache` 方法用于删除 Redis 缓存
- 定时任务中统计景区数据后也调用缓存清除方法
- 调整景区统计任务时间并扩展统计周期为近7天
- 增强定时任务日志记录和异常处理机制
2025-10-31 13:46:17 +08:00

118 lines
4.7 KiB
Java

package com.ycwl.basic.task;
import cn.hutool.core.date.DateUtil;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.mapper.ScenicDeviceStatsMapper;
import com.ycwl.basic.mapper.StatisticsMapper;
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenicDeviceStats.entity.ScenicDeviceStatsEntity;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.AppStatisticsService;
import com.ycwl.basic.utils.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
@Slf4j
@Component
@EnableScheduling
@Profile("prod")
public class ScenicStatsTask {
@Autowired
private ScenicDeviceStatsMapper mapper;
@Autowired
private StatisticsMapper statisticsMapper;
@Autowired
private AppStatisticsService statisticsService;
@Autowired
private ScenicRepository scenicRepository;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Scheduled(cron = "0 1 0 * * *")
public void countDeviceStats() {
Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday());
Date yesterdayEnd = DateUtil.endOfDay(yesterdayStart);
Date twoDaysBeforeStart = DateUtil.beginOfDay(DateUtil.offsetDay(DateUtil.yesterday(), -1));
Date twoDaysBeforeEnd = DateUtil.endOfDay(twoDaysBeforeStart);
// 前天的数据
List<ScenicDeviceStatsEntity> list = mapper.countDeviceStats(twoDaysBeforeStart, twoDaysBeforeEnd);
if (!list.isEmpty()) {
list.forEach(stats -> {
stats.setDate(twoDaysBeforeStart);
mapper.insert(stats);
});
}
list = mapper.countDeviceStats(yesterdayStart, yesterdayEnd);
if (!list.isEmpty()) {
list.forEach(stats -> {
stats.setDate(yesterdayStart);
mapper.insert(stats);
});
}
}
@Scheduled(cron = "0 0 2 * * *")
public void countScenicStats() {
log.info("开始执行景区统计任务,统计前7天至昨天的数据");
// 获取所有景区列表
ScenicReqQuery query = new ScenicReqQuery();
query.setPageSize(1000);
List<ScenicV2DTO> scenicList = scenicRepository.list(query);
// 循环统计前7天(至昨天)的数据
for (int daysAgo = 1; daysAgo <= 7; daysAgo++) {
Date targetDate = DateUtil.offsetDay(new Date(), -daysAgo);
Date startTime = DateUtil.beginOfDay(targetDate);
Date endTime = DateUtil.endOfDay(targetDate);
log.info("正在统计第{}天前的数据,日期: {}", daysAgo, DateUtil.formatDate(startTime));
scenicList.forEach((scenic) -> {
try {
CommonQueryReq commonQueryReq = new CommonQueryReq();
Long scenicId = Long.valueOf(scenic.getId());
commonQueryReq.setScenicId(scenicId);
commonQueryReq.setStartTime(startTime);
commonQueryReq.setEndTime(endTime);
commonQueryReq.setRealtime(true);
// 执行统计查询
ApiResponse<AppStatisticsFunnelVO> resp = statisticsService.userConversionFunnel(commonQueryReq);
AppStatisticsFunnelVO data = resp.getData();
// 写入数据库(REPLACE INTO 会自动更新已存在的记录)
statisticsMapper.insertStat(scenicId, startTime, data);
// 删除该景区的缓存,确保下次查询时获取最新数据
invalidateStatisticsCache(scenicId);
} catch (Exception e) {
log.error("统计景区 {} 在日期 {} 的数据时发生错误", scenic.getId(), DateUtil.formatDate(startTime), e);
}
});
log.info("第{}天前的数据统计完成,日期: {}", daysAgo, DateUtil.formatDate(startTime));
}
log.info("景区统计任务执行完成");
}
/**
* 删除景区统计缓存
* @param scenicId 景区ID
*/
private void invalidateStatisticsCache(Long scenicId) {
String redisKey = "statistics:tmp_cache:" + scenicId;
redisTemplate.delete(redisKey);
}
}