From 621e07803152fb45703f085a27ccf8f4bd3ce361 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Sat, 6 Jun 2026 07:44:59 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BC=A9=E5=B0=8F=E6=97=A5=E5=BF=97=E4=BA=8B?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/stats/AppAccessStatsServiceImpl.java | 156 +++++++++--------- .../task/AppAccessStatsAggregateTask.java | 2 +- 2 files changed, 83 insertions(+), 75 deletions(-) diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/stats/AppAccessStatsServiceImpl.java b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/stats/AppAccessStatsServiceImpl.java index a8e20df7c..5b4d30808 100644 --- a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/stats/AppAccessStatsServiceImpl.java +++ b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/stats/AppAccessStatsServiceImpl.java @@ -3,9 +3,9 @@ package com.bsd.pjcloud.admin.service.impl.stats; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.bsd.pjcloud.admin.api.dto.stats.AppAccessStatsQueryDTO; import com.bsd.pjcloud.admin.api.dto.stats.AppAccessTrackRequestDTO; import com.bsd.pjcloud.admin.api.entity.SysDept; @@ -26,6 +26,7 @@ import com.bsd.pjcloud.common.security.util.SecurityUtils; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -51,16 +52,10 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService { private final SysDeptMapper sysDeptMapper; @Override - @Transactional(rollbackFor = Exception.class) public R track(AppAccessTrackRequestDTO dto, HttpServletRequest request) { if (!isPageCodeEnabled(dto.getPageCode())) { return R.failed("pageCode未在埋点字典中启用: " + dto.getPageCode()); } - Long exists = appAccessEventMapper.selectCount(new LambdaQueryWrapper() - .eq(AppAccessEventEntity::getEventId, dto.getEventId())); - if (exists != null && exists > 0) { - return R.ok(Boolean.TRUE); - } LocalDateTime eventTime = ObjectUtil.defaultIfNull(dto.getEventTime(), LocalDateTime.now()); PjcloudUser loginUser = SecurityUtils.getUser(); @@ -85,7 +80,11 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService { entity.setUnitName(orgInfo.unitName); entity.setDeptId(orgInfo.deptId); entity.setDeptName(orgInfo.deptName); - appAccessEventMapper.insert(entity); + try { + appAccessEventMapper.insert(entity); + } catch (DuplicateKeyException ex) { + return R.ok(Boolean.TRUE); + } return R.ok(Boolean.TRUE); } @@ -262,34 +261,19 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService { } @Override - @Transactional(rollbackFor = Exception.class) public void aggregateLastMinute() { LocalDateTime end = LocalDateTime.now().withSecond(0).withNano(0); LocalDateTime start = end.minusMinutes(1); + List> rows = queryEventAggRows(start, end); + getSelf().persistMinuteAggregation(start, rows); + } - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.select( - "tenant_id as tenantId", - "unit_id as unitId", - "max(unit_name) as unitName", - "dept_id as deptId", - "max(dept_name) as deptName", - "page_code as pageCode", - "count(1) as pv", - "count(distinct if(user_id is null, concat('D_', ifnull(device_id,'')), concat('U_', user_id))) as uv", - "count(distinct user_id) as visitUserCount", - "count(1) as trackCount" - ); - queryWrapper.ge("event_time", start); - queryWrapper.lt("event_time", end); - queryWrapper.groupBy("tenant_id", "unit_id", "dept_id", "page_code"); - List> rows = appAccessEventMapper.selectMaps(queryWrapper); - + @Transactional(rollbackFor = Exception.class) + public void persistMinuteAggregation(LocalDateTime start, List> rows) { appAccessAggMinuteMapper.deletePhysicallyByBucketTime(start); if (CollUtil.isEmpty(rows)) { return; } - for (Map row : rows) { AppAccessAggMinuteEntity entity = new AppAccessAggMinuteEntity(); entity.setBucketTime(start); @@ -308,52 +292,63 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService { } @Override - @Transactional(rollbackFor = Exception.class) public void aggregateRecentDays(int dayCount) { int safeDayCount = Math.max(dayCount, 1); LocalDate today = LocalDate.now(); for (int i = 0; i < safeDayCount; i++) { LocalDate date = today.minusDays(i); - LocalDateTime start = date.atStartOfDay(); - LocalDateTime end = start.plusDays(1); - - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.select( - "tenant_id as tenantId", - "unit_id as unitId", - "max(unit_name) as unitName", - "dept_id as deptId", - "max(dept_name) as deptName", - "page_code as pageCode", - "count(1) as pv", - "count(distinct if(user_id is null, concat('D_', ifnull(device_id,'')), concat('U_', user_id))) as uv", - "count(distinct user_id) as visitUserCount", - "count(1) as trackCount" - ); - queryWrapper.ge("event_time", start); - queryWrapper.lt("event_time", end); - queryWrapper.groupBy("tenant_id", "unit_id", "dept_id", "page_code"); - List> rows = appAccessEventMapper.selectMaps(queryWrapper); - - appAccessAggDayMapper.deletePhysicallyByStatDate(date); - for (Map row : rows) { - AppAccessAggDayEntity entity = new AppAccessAggDayEntity(); - entity.setStatDate(date); - entity.setTenantId(toLongObj(row.get("tenantId"))); - entity.setUnitId(toLongObj(row.get("unitId"))); - entity.setUnitName(Objects.toString(row.get("unitName"), null)); - entity.setDeptId(toLongObj(row.get("deptId"))); - entity.setDeptName(Objects.toString(row.get("deptName"), null)); - entity.setPageCode(Objects.toString(row.get("pageCode"), null)); - entity.setPv(toLong(row.get("pv"))); - entity.setUv(toLong(row.get("uv"))); - entity.setVisitUserCount(toLong(row.get("visitUserCount"))); - entity.setTrackCount(toLong(row.get("trackCount"))); - appAccessAggDayMapper.insert(entity); + try { + List> rows = queryEventAggRows(date.atStartOfDay(), date.plusDays(1).atStartOfDay()); + getSelf().persistDayAggregation(date, rows); + } catch (Exception e) { + log.error("日聚合失败 date={}", date, e); } } } + @Transactional(rollbackFor = Exception.class) + public void persistDayAggregation(LocalDate date, List> rows) { + appAccessAggDayMapper.deletePhysicallyByStatDate(date); + if (CollUtil.isEmpty(rows)) { + return; + } + for (Map row : rows) { + AppAccessAggDayEntity entity = new AppAccessAggDayEntity(); + entity.setStatDate(date); + entity.setTenantId(toLongObj(row.get("tenantId"))); + entity.setUnitId(toLongObj(row.get("unitId"))); + entity.setUnitName(Objects.toString(row.get("unitName"), null)); + entity.setDeptId(toLongObj(row.get("deptId"))); + entity.setDeptName(Objects.toString(row.get("deptName"), null)); + entity.setPageCode(Objects.toString(row.get("pageCode"), null)); + entity.setPv(toLong(row.get("pv"))); + entity.setUv(toLong(row.get("uv"))); + entity.setVisitUserCount(toLong(row.get("visitUserCount"))); + entity.setTrackCount(toLong(row.get("trackCount"))); + appAccessAggDayMapper.insert(entity); + } + } + + private List> queryEventAggRows(LocalDateTime start, LocalDateTime end) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select( + "tenant_id as tenantId", + "unit_id as unitId", + "max(unit_name) as unitName", + "dept_id as deptId", + "max(dept_name) as deptName", + "page_code as pageCode", + "count(1) as pv", + "count(distinct if(user_id is null, concat('D_', ifnull(device_id,'')), concat('U_', user_id))) as uv", + "count(distinct user_id) as visitUserCount", + "count(1) as trackCount" + ); + queryWrapper.ge("event_time", start); + queryWrapper.lt("event_time", end); + queryWrapper.groupBy("tenant_id", "unit_id", "dept_id", "page_code"); + return appAccessEventMapper.selectMaps(queryWrapper); + } + private boolean isPageCodeEnabled(String pageCode) { Long count = appAccessPageDictMapper.selectCount(new LambdaQueryWrapper() .eq(AppAccessPageDictEntity::getPageCode, pageCode) @@ -427,22 +422,35 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService { .last("limit 1")); if (currentSnapshot == null) { - DimUserOrgSnapshotEntity inserted = insertSnapshot(userId, userTenantId, unitDept, dept, eventTime); - return toOrgInfo(inserted); + return getSelf().insertOrgSnapshotTx(userId, userTenantId, unitDept, dept, eventTime); } if (isOrgSnapshotOutdated(currentSnapshot, unitDept, dept)) { - DimUserOrgSnapshotEntity update = new DimUserOrgSnapshotEntity(); - update.setSnapshotSk(currentSnapshot.getSnapshotSk()); - update.setIsCurrent(0); - update.setEffectiveEndTime(eventTime); - dimUserOrgSnapshotMapper.updateById(update); - DimUserOrgSnapshotEntity inserted = insertSnapshot(userId, userTenantId, unitDept, dept, eventTime); - return toOrgInfo(inserted); + return getSelf().rotateOrgSnapshotTx(userId, userTenantId, unitDept, dept, eventTime, currentSnapshot); } return toOrgInfo(currentSnapshot); } + @Transactional(rollbackFor = Exception.class) + public OrgInfo insertOrgSnapshotTx(Long userId, Long tenantId, SysDept unitDept, SysDept dept, LocalDateTime eventTime) { + return toOrgInfo(insertSnapshot(userId, tenantId, unitDept, dept, eventTime)); + } + + @Transactional(rollbackFor = Exception.class) + public OrgInfo rotateOrgSnapshotTx(Long userId, Long tenantId, SysDept unitDept, SysDept dept, LocalDateTime eventTime, + DimUserOrgSnapshotEntity currentSnapshot) { + DimUserOrgSnapshotEntity update = new DimUserOrgSnapshotEntity(); + update.setSnapshotSk(currentSnapshot.getSnapshotSk()); + update.setIsCurrent(0); + update.setEffectiveEndTime(eventTime); + dimUserOrgSnapshotMapper.updateById(update); + return toOrgInfo(insertSnapshot(userId, tenantId, unitDept, dept, eventTime)); + } + + private AppAccessStatsServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + private DimUserOrgSnapshotEntity insertSnapshot(Long userId, Long tenantId, SysDept unitDept, SysDept dept, LocalDateTime eventTime) { DimUserOrgSnapshotEntity snapshot = new DimUserOrgSnapshotEntity(); snapshot.setUserId(userId); diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/task/AppAccessStatsAggregateTask.java b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/task/AppAccessStatsAggregateTask.java index ee0ab8904..7a98653c9 100644 --- a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/task/AppAccessStatsAggregateTask.java +++ b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/task/AppAccessStatsAggregateTask.java @@ -22,7 +22,7 @@ public class AppAccessStatsAggregateTask { } } - @Scheduled(cron = "0 10 * * * ?") + @Scheduled(cron = "0 15 * * * ?") public void aggregateDay() { try { appAccessStatsService.aggregateRecentDays(2);