This commit is contained in:
otto 2026-07-29 16:03:03 +08:00
commit 73b42af29f
4 changed files with 158 additions and 9 deletions

View File

@ -249,6 +249,18 @@ public class CacheConstants {
return ZONE_PROJECT_SORT_BY_SCORE + "*:" + zoneId + ":*";
}
/**
* 专区统计数据缓存前缀
*/
private final static String ZONE_STATISTICS_KEY = "zone:statistics:";
/**
* 获取专区统计数据缓存key
*/
public static String getZoneStatisticsKey(Long zoneId) {
return ZONE_STATISTICS_KEY + zoneId;
}
/**
* 文件打包是否完成0代表未完成1代表已完成-1代表打包失败需要重新打包
*/

View File

@ -237,6 +237,14 @@ public interface IZoneDetailService {
ZoneStatisticsVo getZoneStatistics(Long zoneId);
/**
* 计算专区统计数据内部方法用于定时任务调用
*
* @param zoneId 专区ID
* @return 统计数据
*/
ZoneStatisticsVo calculateZoneStatistics(Long zoneId);
/**
* 判断专区是否为积分专区
*

View File

@ -56,6 +56,7 @@ import com.microservices.zone.resource.mapper.ZoneResourceTypeMapper;
import com.microservices.zone.specialProject.domain.ZoneSpecialProject;
import com.microservices.zone.specialProject.service.IZoneSpecialProjectService;
import com.microservices.zone.utils.ZoneConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
@ -67,6 +68,7 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@ -76,6 +78,7 @@ import java.util.stream.Collectors;
* @date 2023-05-09
*/
@Service
@Slf4j
public class ZoneDetailServiceImpl implements IZoneDetailService {
@Autowired
private ZoneDetailMapper zoneDetailMapper;
@ -224,13 +227,13 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
Date[] lastWeek = getLastWeek();
//专区文章数统计
ZoneDetailDataVo articlesGroupByKey = zoneDetailMapper
.countArticlesGroupByKey(lastWeek[0], lastWeek[1], zoneDetail.getKey());
.countArticlesGroupByKey(lastWeek[0],lastWeek[1],zoneDetail.getKey()) ;
if (articlesGroupByKey != null) {
zoneDetailDataVo.setWeekArticles(articlesGroupByKey.getWeekArticles());
}
//专区浏览数据统计
ZoneDetailDataVo puVsGroupByKey = zoneDetailMapper
.countPUVsGroupByKey(lastWeek[0], lastWeek[1], zoneDetail.getKey());
.countPUVsGroupByKey(lastWeek[0],lastWeek[1],zoneDetail.getKey()) ;
if (puVsGroupByKey != null) {
zoneDetailDataVo.setWeekPV(puVsGroupByKey.getWeekPV());
zoneDetailDataVo.setWeekUV(puVsGroupByKey.getWeekUV());
@ -917,17 +920,32 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
}
@Override
public ZoneStatisticsVo getZoneStatistics(Long zoneId) {
public ZoneStatisticsVo calculateZoneStatistics(Long zoneId) {
ZoneStatisticsVo zoneStatisticsVo = new ZoneStatisticsVo();
ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailById(zoneId);
Set<String> usernameSet = new HashSet<>();
// 获取专区会员数
ZoneMember zoneMemberSearch = new ZoneMember();
zoneMemberSearch.setZoneId(zoneId);
zoneMemberSearch.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
Integer zoneMemberCount = zoneMemberMapper.selectCountByZoneId(zoneMemberSearch);
ZoneMemberSearchVo zoneMemberSearchVo = new ZoneMemberSearchVo();
zoneMemberSearchVo.setZoneId(zoneId);
List<ZoneMember> zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearchVo);
zoneMemberList.forEach(x -> {
if (x.getSysUser() != null) {
usernameSet.add(x.getSysUser().getUserName());
}
});
// 获取专区内用户列表
GenericsTableDataInfo<SysUserDeptRole> userTable = FeignUtils.getReturnData(
remoteUserService.searchUserIdentifierListByDept(zoneDetail.getDeptId(), null, null, null, SecurityConstants.INNER)
);
if (userTable != null && userTable.getTotal() > 0) {
userTable.getRows().forEach(x -> {
if (x.getSysUser() != null) {
usernameSet.add(x.getSysUser().getUserName());
}
});
}
// 获取仓库贡献者数量
ZoneProjectSearchVo zoneProjectSearchVo = new ZoneProjectSearchVo();
zoneProjectSearchVo.setZoneId(zoneId);
@ -948,7 +966,7 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
}
}
}
zoneStatisticsVo.setCommunityUserCount((long) usernameSet.size() + zoneMemberCount);
zoneStatisticsVo.setCommunityUserCount((long) usernameSet.size());
Long cmsDocCount = FeignUtils.getReturnData(remoteCmsService.getCmsCountByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER));
zoneStatisticsVo.setCmsDocCount(cmsDocCount == null ? 0L : cmsDocCount);
Long cmsDocVisits = FeignUtils.getReturnData(remoteCmsService.getCmsDocVisitsByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER));
@ -956,7 +974,8 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
ZoneResource zoneResource = new ZoneResource();
zoneResource.setZoneId(zoneId);
zoneStatisticsVo.setResourceCount(Long.valueOf(zoneResourceMapper.selectZoneResourceCount(zoneResource)));
List<ZoneResource> zoneResourceList = zoneResourceMapper.selectZoneResourceList(zoneResource);
zoneStatisticsVo.setResourceCount((long) zoneResourceList.size());
ZoneSpecialProject zoneSpecialProject = new ZoneSpecialProject();
zoneSpecialProject.setZoneId(zoneId);
@ -966,6 +985,35 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
return zoneStatisticsVo;
}
@Override
public ZoneStatisticsVo getZoneStatistics(Long zoneId) {
String cacheKey = CacheConstants.getZoneStatisticsKey(zoneId);
try {
// 1. 尝试从Redis缓存获取
ZoneStatisticsVo cachedStatistics = redisService.getCacheObject(cacheKey);
if (cachedStatistics != null) {
log.debug("专区[{}]统计数据来自缓存", zoneId);
return cachedStatistics;
}
} catch (Exception e) {
log.warn("专区[{}]统计数据缓存读取失败,执行降级逻辑", zoneId, e);
}
// 2. 缓存异常或未命中执行实时计算
log.info("专区[{}]统计数据缓存未命中,执行实时计算", zoneId);
ZoneStatisticsVo statistics = calculateZoneStatistics(zoneId);
// 3. 尝试缓存计算结果失败不影响主流程
try {
redisService.setCacheObject(cacheKey, statistics, 7200L, TimeUnit.SECONDS);
} catch (Exception e) {
log.warn("专区[{}]统计数据缓存写入失败", zoneId, e);
}
return statistics;
}
@Override
public boolean isPointsZone(Long zoneId) {
ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailById(zoneId);

View File

@ -0,0 +1,81 @@
package com.microservices.zone.task;
import com.microservices.common.core.constant.CacheConstants;
import com.microservices.common.redis.service.RedisService;
import com.microservices.zone.detail.domain.vo.ZoneBaseDataVo;
import com.microservices.zone.detail.service.IZoneDetailService;
import com.microservices.zone.project.domain.vo.ZoneStatisticsVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 专区统计数据预计算定时任务
*/
@Component
public class ZoneStatisticsJob {
private static final Logger logger = LoggerFactory.getLogger(ZoneStatisticsJob.class);
@Autowired
private IZoneDetailService zoneDetailService;
@Autowired
private RedisService redisService;
/**
* 应用启动时执行专区统计数据预计算
* 确保服务启动后接口立即可用
*/
@PostConstruct
public void initZoneStatistics() {
logger.info("应用启动,执行专区统计数据初始化");
calculateZoneStatistics();
}
/**
* 每小时执行一次专区统计数据预计算
* cron表达式: 每小时的第5分钟执行
*/
@Scheduled(cron = "0 5 * * * ?")
public void calculateZoneStatistics() {
logger.info("开始执行专区统计数据预计算任务");
try {
// 获取所有已发布的专区列表
List<ZoneBaseDataVo> zoneList = zoneDetailService.selectPublishedZoneBaseList();
logger.info("发现已发布专区数量: {}", zoneList.size());
int successCount = 0;
int failCount = 0;
for (ZoneBaseDataVo zone : zoneList) {
try {
// 计算单个专区的统计数据
ZoneStatisticsVo statistics = zoneDetailService.calculateZoneStatistics(zone.getId());
// 存储到Redis缓存
String cacheKey = CacheConstants.getZoneStatisticsKey(zone.getId());
redisService.setCacheObject(cacheKey, statistics, 7200L, TimeUnit.SECONDS);
successCount++;
logger.debug("专区[{}]统计数据计算完成", zone.getId());
} catch (Exception e) {
failCount++;
logger.error("专区[{}]统计数据计算失败", zone.getId(), e);
}
}
logger.info("专区统计数据预计算任务完成 - 成功: {}, 失败: {}", successCount, failCount);
} catch (Exception e) {
logger.error("专区统计数据预计算任务执行失败", e);
}
}
}