From 7e5127b078aff9f71389677b90e081255f9145f9 Mon Sep 17 00:00:00 2001 From: otto <731554297@qq.com> Date: Wed, 29 Jul 2026 16:00:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=B6=85=E7=AE=97=E4=B8=93=E5=8C=BA):=20?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E7=BB=9F=E8=AE=A1=E4=B8=93=E5=8C=BA=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E7=BB=9F=E8=AE=A1=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E8=BE=83=E6=85=A2=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/core/constant/CacheConstants.java | 12 +++ .../detail/service/IZoneDetailService.java | 8 ++ .../service/impl/ZoneDetailServiceImpl.java | 66 ++++++++++++--- .../zone/task/ZoneStatisticsJob.java | 81 +++++++++++++++++++ 4 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/task/ZoneStatisticsJob.java diff --git a/microservices-common/microservices-common-core/src/main/java/com/microservices/common/core/constant/CacheConstants.java b/microservices-common/microservices-common-core/src/main/java/com/microservices/common/core/constant/CacheConstants.java index 342f91498..c848b5123 100644 --- a/microservices-common/microservices-common-core/src/main/java/com/microservices/common/core/constant/CacheConstants.java +++ b/microservices-common/microservices-common-core/src/main/java/com/microservices/common/core/constant/CacheConstants.java @@ -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:代表打包失败,需要重新打包) */ diff --git a/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/detail/service/IZoneDetailService.java b/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/detail/service/IZoneDetailService.java index d46794de4..e91ba796c 100644 --- a/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/detail/service/IZoneDetailService.java +++ b/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/detail/service/IZoneDetailService.java @@ -237,6 +237,14 @@ public interface IZoneDetailService { ZoneStatisticsVo getZoneStatistics(Long zoneId); + /** + * 计算专区统计数据(内部方法,用于定时任务调用) + * + * @param zoneId 专区ID + * @return 统计数据 + */ + ZoneStatisticsVo calculateZoneStatistics(Long zoneId); + /** * 判断专区是否为积分专区 * diff --git a/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/detail/service/impl/ZoneDetailServiceImpl.java b/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/detail/service/impl/ZoneDetailServiceImpl.java index 607447720..db8d35d38 100644 --- a/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/detail/service/impl/ZoneDetailServiceImpl.java +++ b/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/detail/service/impl/ZoneDetailServiceImpl.java @@ -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 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 zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearchVo); + zoneMemberList.forEach(x -> { + if (x.getSysUser() != null) { + usernameSet.add(x.getSysUser().getUserName()); + } + }); + // 获取专区内用户列表 + GenericsTableDataInfo 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 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); diff --git a/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/task/ZoneStatisticsJob.java b/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/task/ZoneStatisticsJob.java new file mode 100644 index 000000000..a6e090322 --- /dev/null +++ b/microservices-modules/microservices-modules-zone/src/main/java/com/microservices/zone/task/ZoneStatisticsJob.java @@ -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 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); + } + } +} \ No newline at end of file