Merge remote-tracking branch 'origin/main'

This commit is contained in:
2025-12-09 17:22:50 +08:00
22 changed files with 351 additions and 25 deletions

View File

@@ -0,0 +1,55 @@
package com.sdm.data.job;
import com.alibaba.fastjson2.JSON;
import com.sdm.common.common.SdmResponse;
import com.sdm.common.common.ThreadLocalContext;
import com.sdm.common.entity.enums.MessageTemplateEnum;
import com.sdm.common.entity.req.system.SendMsgReq;
import com.sdm.common.feign.impl.system.MessageFeignClientImpl;
import com.sdm.data.model.entity.FileStorageQuota;
import com.sdm.data.service.DataStorageAnalysis;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
@RequiredArgsConstructor
public class DataStorageMonitorJob {
private final DataStorageAnalysis dataStorageAnalysis;
private final MessageFeignClientImpl messageFeignClient;
/**
* 定时筛选存储空间达到阈值的用户 发送告警消息
*/
@Scheduled(cron = "${data.storage-monitor.cron:0 */1 * * * ?}")
public void checkDataStorageSpaceAndSendAlert() {
log.info("开始执行定时筛选存储空间达到阈值的用户任务");
try {
SdmResponse<List<FileStorageQuota>> sdmResponse = dataStorageAnalysis.listAllUserQuotaForJob();
if (CollectionUtils.isNotEmpty(sdmResponse.getData())) {
List<FileStorageQuota> fileStorageQuotaList = sdmResponse.getData();
fileStorageQuotaList.forEach(quota -> {
SendMsgReq req = new SendMsgReq();
req.setTitle(MessageTemplateEnum.DATA_ALERT.getTitle());
req.setContent(MessageTemplateEnum.DATA_ALERT.getContent());
req.setTenantId(String.valueOf(quota.getTenantId()));
req.setUserId(String.valueOf(quota.getUserId()));
log.info("[DataStorageMonitorJob] checkDataStorageSpaceAndSendAlert param:{}", JSON.toJSONString(req));
messageFeignClient.sendMessage(req);
});
}
log.info("定时筛选存储空间达到阈值的用户任务执行完成");
} catch (Exception e) {
log.error("定时筛选存储空间达到阈值的用户任务执行失败", e);
}
}
}

View File

@@ -3,6 +3,7 @@ package com.sdm.data.service;
import com.sdm.common.common.SdmResponse;
import com.sdm.common.entity.resp.PageDataResp;
import com.sdm.data.model.entity.FileStorage;
import com.sdm.data.model.entity.FileStorageQuota;
import com.sdm.data.model.req.AddUserQuotaEntity;
import com.sdm.data.model.req.ListUserQuotaReq;
import com.sdm.data.model.req.QueryBigFileReq;
@@ -45,4 +46,6 @@ public interface DataStorageAnalysis {
List<Long> getListBigFileId(QueryBigFileReq queryBigFileReq);
SdmResponse<List<FileStorageQuota>> listAllUserQuotaForJob();
}

View File

@@ -1,5 +1,6 @@
package com.sdm.data.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@@ -35,6 +36,7 @@ import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
@@ -280,7 +282,7 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis {
// 构造最终结果,对于没有配额信息的用户添加默认值,并根据已使用存储量设置状态
List<FileStorageQuota> fullList = userIds.stream().map(userId -> {
FileStorageQuota quota = quotaMap.getOrDefault(userId, createDefaultFileStorageQuota(userId));
FileStorageQuota quota = quotaMap.getOrDefault(userId, createDefaultFileStorageQuota(userId, tenantId));
// 设置已使用值
UserTotalFileSizeDTO usedStorage = usedStorageMap.get(userId);
if (usedStorage != null) {
@@ -324,13 +326,18 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis {
}
// 辅助方法:创建默认的 FileStorageQuota 实例
private FileStorageQuota createDefaultFileStorageQuota(Long userId) {
private FileStorageQuota createDefaultFileStorageQuota(Long userId, Long tenantId) {
FileStorageQuota defaultQuota = new FileStorageQuota();
defaultQuota.setUserId(userId);
defaultQuota.setTenantId(tenantId);
defaultQuota.setQuotaValue(2L); // 默认存储阈值
defaultQuota.setQuotaUnit("GB"); // 默认单位
defaultQuota.setUsedValue(0L); // 默认已使用值
defaultQuota.setStatus("NORMAL"); // 默认状态
// 初始化到表里 存储告警查询使用
if (CollectionUtils.isEmpty(fileStorageQuotaService.lambdaQuery().eq(FileStorageQuota::getUserId, userId).list())) {
fileStorageQuotaService.save(defaultQuota);
}
return defaultQuota;
}
@@ -376,4 +383,26 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis {
.map(FileStorage::getFileId)
.collect(Collectors.toList());
}
@Override
public SdmResponse<List<FileStorageQuota>> listAllUserQuotaForJob() {
List<FileStorageQuota> quotaList = fileStorageQuotaService.list();
for (FileStorageQuota quota : quotaList) {
// fileStorageService 查询用户已使用的存储空间
List<UserTotalFileSizeDTO> userStorageList = fileStorageService.getTotalFileSizeByCreator(Arrays.asList(quota.getUserId()), null,quota.getTenantId());
if (CollUtil.size(userStorageList) > 0) {
UserTotalFileSizeDTO usedStorage = userStorageList.get(0);
quota.setUsedValue(usedStorage.getTotalSize());
// 根据配额和已使用量设置状态
if (quota.getQuotaValue() != null && quota.getUsedValue() != null) {
// 将配额值转换为与已使用值相同的单位(字节)进行比较
long quotaInBytes = convertToBytes(quota.getQuotaValue(), quota.getQuotaUnit());
if (quotaInBytes <= quota.getUsedValue()) {
quota.setStatus("EXCEED");
}
}
}
}
return SdmResponse.success(quotaList.stream().filter(i -> "EXCEED".equals(i.getStatus())).toList());
}
}

View File

@@ -14,8 +14,12 @@ import com.sdm.common.entity.req.data.DelDirReq;
import com.sdm.common.entity.req.data.DelFileReq;
import com.sdm.common.entity.req.data.UploadFilesReq;
import com.sdm.common.entity.req.project.DelNodeReq;
import com.sdm.common.entity.req.system.UserQueryReq;
import com.sdm.common.entity.resp.AllNodeByProjectIdAndTypeResp;
import com.sdm.common.entity.resp.system.CIDUserResp;
import com.sdm.common.feign.impl.project.SimulationNodeFeignClientImpl;
import com.sdm.common.feign.impl.system.SysUserFeignClientImpl;
import com.sdm.common.utils.CidSysUserUtil;
import com.sdm.common.utils.PageUtils;
import com.sdm.data.model.entity.DimensionTemplate;
import com.sdm.data.dao.DimensionTemplateMapper;
@@ -40,9 +44,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Stream;
/**
@@ -68,6 +70,9 @@ public class DimensionTemplateServiceImpl extends ServiceImpl<DimensionTemplateM
@Autowired
IFileMetadataInfoService fileMetadataInfoService;
@Autowired
private SysUserFeignClientImpl sysUserFeignClient;
@Override
@Transactional(rollbackFor = Exception.class)
public SdmResponse saveDimensionTemplateWithHierarchies(TemplateCreationRequest request) {
@@ -310,11 +315,46 @@ public class DimensionTemplateServiceImpl extends ServiceImpl<DimensionTemplateM
PageHelper.startPage(req.getCurrent(), req.getSize());
List<FileMetadataInfo> fileMetadataInfos = fileMetadataInfoService.listSimulationNodeFiles(parentDirId, dirInfos,req.isFilterEmptyData(),tenantId);
setCreatorNames(fileMetadataInfos);
PageInfo<FileMetadataInfo> page = new PageInfo<>(fileMetadataInfos);
return PageUtils.getJsonObjectSdmResponse(fileMetadataInfos, page);
}
private void setCreatorNames(List<FileMetadataInfo> list) {
try {
if (ObjectUtils.isNotEmpty(list)) {
// 提取去重的 creatorId
List<Long> creatorIds = list.stream()
.map(FileMetadataInfo::getCreatorId)
.filter(Objects::nonNull)
.distinct()
.toList();
// 远程查询用户信息
SdmResponse<List<CIDUserResp>> userListSdmRsp = sysUserFeignClient.listUserByIds(
UserQueryReq.builder().userIds(creatorIds).build()
);
// 批量设置 creatorName
if (userListSdmRsp.isSuccess() && CollectionUtils.isNotEmpty(userListSdmRsp.getData())) {
Map<Long, CIDUserResp> cidUserMap = CidSysUserUtil.getCidUserToMap(userListSdmRsp.getData());
list.forEach(fileMetadataInfo -> {
Long creatorId = fileMetadataInfo.getCreatorId();
CIDUserResp cidUser = cidUserMap.get(creatorId);
String username = Objects.isNull(cidUser) ? "" : org.apache.commons.lang3.StringUtils.firstNonBlank(
cidUser.getNickname(),
cidUser.getUsername(),
cidUser.getRealName()
);
fileMetadataInfo.setCreatorName(username);
});
}
}
} catch (Exception e) {
log.error("setCreatorNames error:{}",e.getMessage());
}
}
@Override
public SdmResponse createSimulationNodeDir(CreateDirReq req) {
req.setDirType(DirTypeEnum.PROJECT_NODE_DIR.getValue());

View File

@@ -125,4 +125,8 @@ security:
- /data/downloadFile
- /data/flowableUpFileToLocal
- /data/flowableUpFileToLocalMerge
- /data/getFileBaseInfo
- /data/getFileBaseInfo
data:
storage-monitor:
cron: 0 0 9 * * ?

View File

@@ -132,6 +132,10 @@ security:
- /data/flowableUpFileToLocalMerge
- /data/getFileBaseInfo
data:
storage-monitor:
cron: 0 0 9 * * ?
# 0单机处理可以指向本地1负载均衡轮询
serverType: 0
#serverIp: 192.168.65.161