diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..bc7e164d --- /dev/null +++ b/.gitignore @@ -0,0 +1,80 @@ +/outbridge/target/classes/com/sdm/outbridge/config/CommonConfig$YamlPropertySourceFactory.class +/outbridge/target/classes/com/sdm/outbridge/config/CommonConfig.class +/outbridge/target/classes/com/sdm/outbridge/config/DataSourcePreWarmer.class +/outbridge/target/classes/com/sdm/outbridge/config/SecondMybatisPlusConfig.class +/outbridge/target/classes/com/sdm/outbridge/config/ThirdMybatisPlusConfig.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVMainPlanDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVPdtToDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVProductionLineToDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVProjectBatchToDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVProjectResourcePlanDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVProjectStationExcepTionToDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVProjectStationPlanToDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVProjectStationToDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVProjectToDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVTodoEmulationInfoDM.class +/outbridge/target/classes/com/sdm/outbridge/entity/LyricVUserToDm.class +/outbridge/target/classes/com/sdm/outbridge/mode/FreelinkAndDingdingInformReq.class +/outbridge/target/classes/com/sdm/outbridge/mode/FreeLinkMsg.class +/outbridge/target/classes/com/sdm/outbridge/mode/FreeLinkParamDto.class +/outbridge/target/classes/com/sdm/outbridge/mode/FreeLinkResp.class +/outbridge/target/classes/com/sdm/outbridge/mode/GetProcessDataCondition.class +/outbridge/target/classes/com/sdm/outbridge/mode/GetProcessDataReq.class +/outbridge/target/classes/com/sdm/outbridge/mode/GetUserListReq.class +/outbridge/target/classes/com/sdm/outbridge/mode/HkCloudSignObject.class +/outbridge/target/classes/com/sdm/outbridge/mode/HkUploadFileReq.class +/outbridge/target/classes/com/sdm/outbridge/mode/LyricAttachmentInfo.class +/outbridge/target/classes/com/sdm/outbridge/mode/LyricExceptionModel.class +/outbridge/target/classes/com/sdm/outbridge/mode/LyricMainPlanInfo.class +/outbridge/target/classes/com/sdm/outbridge/mode/LyricProjectBaseInfo.class +/outbridge/target/classes/com/sdm/outbridge/mode/LyricProjectBatchInfo.class +/outbridge/target/classes/com/sdm/outbridge/mode/LyricProjectPdt.class +/outbridge/target/classes/com/sdm/outbridge/mode/LyricTodoEntity.class +/outbridge/target/classes/com/sdm/outbridge/mode/SimulationTaskSyncExBo.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/DynamicSqlExecutorMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVMainPlanDMMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVPdtDmMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVProductionLineToDmMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVProjectBatchToDMMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVProjectResourcePlanDMMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVProjectStationPlanToDmMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVProjectStationToDmMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVProjectToDmMapper.class +/outbridge/target/classes/com/sdm/outbridge/secondDao/LyricVTodoInfoMapper.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/FreeLinkServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVMainPlanDMServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVPdtDmServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVProductionLineToDmServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVProjectBatchToDMServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVProjectResourcePlanDMServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVProjectStationExcepTionToDMServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVProjectStationPlanToDmServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVProjectStationToDmServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVProjectToDmServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/impl/lyric/LyricVTodoInfoServiceImpl.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/IFreeLinkService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricIntegrateService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVMainPlanDMService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVPdtDmService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVProductionLineToDmService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVProjectBatchToDmService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVProjectResourcePlanDMService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVProjectStationExcepTionToDMService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVProjectStationPlanToDmService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVProjectStationToDmService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVProjectToDmService.class +/outbridge/target/classes/com/sdm/outbridge/service/lyric/LyricVTodoInfoService.class +/outbridge/target/classes/com/sdm/outbridge/thirdDao/DynamicSqlThirdExecutorMapper.class +/outbridge/target/classes/com/sdm/outbridge/thirdDao/LyricVProjectStationExcepTionToDMMapper.class +/outbridge/target/classes/META-INF/spring-configuration-metadata.json +/outbridge/target/classes/thirdDaoMapper/LyricVProjectStationExcepTionToDMMapper.xml +/outbridge/target/classes/common-dev-65.yml +/outbridge/target/classes/common-dev-190.yml +/outbridge/target/classes/common-local.yml +/outbridge/target/classes/common-lyric.yml +/outbridge/target/classes/common-test.yml +/outbridge/target/classes/common-yian.yml +/outbridge/target/maven-archiver/pom.properties +/outbridge/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +/outbridge/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +/outbridge/target/outbridge-0.0.1-SNAPSHOT.jar diff --git a/common/src/main/java/com/sdm/common/annotation/AutoFillDictTags.java b/common/src/main/java/com/sdm/common/annotation/AutoFillDictTags.java new file mode 100644 index 00000000..f3258340 --- /dev/null +++ b/common/src/main/java/com/sdm/common/annotation/AutoFillDictTags.java @@ -0,0 +1,55 @@ +package com.sdm.common.annotation; + +import java.lang.annotation.*; + +/** + * 自动填充字典标签注解 + * 可标注在 Controller 方法、Service 方法或 Service 类上,会自动查询并填充请求参数中的字典标签ID + * + * 使用场景: + * 1. Controller 层:标注在接口方法上,处理前端请求参数 + * 2. Service 层:标注在服务方法上,处理内部调用的参数 + * 3. Service 类:标注在类上,该类所有 public 方法都会自动处理 + * + * 使用示例: + *
+ * // 示例1:Controller 方法
+ * @AutoFillDictTags
+ * @PostMapping("/upload")
+ * public SdmResponse upload(@RequestBody UploadFilesReq req) {
+ *     // req.getDictTagIdsCache() 已经被自动填充
+ *     return service.upload(req);
+ * }
+ * 
+ * // 示例2:Service 方法
+ * @AutoFillDictTags
+ * public SdmResponse processData(UploadFilesReq req) {
+ *     // req.getDictTagIdsCache() 已经被自动填充
+ *     Map> tagIds = req.getDictTagIdsCache();
+ * }
+ * 
+ * // 示例3:Service 类(推荐用于内部调用较多的场景)
+ * @Service
+ * @AutoFillDictTags
+ * public class DataProcessService {
+ *     // 该类所有方法的 dictTags 参数都会自动处理
+ * }
+ * 
+ */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AutoFillDictTags { + + /** + * 指定要处理的参数名称,默认处理所有参数 + * @return 参数名称数组 + */ + String[] paramNames() default {}; + + /** + * 是否忽略空的dictTags,默认true + * @return true表示dictTags为空时不处理,false表示仍然尝试处理 + */ + boolean ignoreEmpty() default true; +} diff --git a/common/src/main/java/com/sdm/common/aspect/DictTagsAutoFillAspect.java b/common/src/main/java/com/sdm/common/aspect/DictTagsAutoFillAspect.java new file mode 100644 index 00000000..c0080ab4 --- /dev/null +++ b/common/src/main/java/com/sdm/common/aspect/DictTagsAutoFillAspect.java @@ -0,0 +1,163 @@ +package com.sdm.common.aspect; + +import com.sdm.common.annotation.AutoFillDictTags; +import com.sdm.common.utils.DictTagHelper; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 字典标签自动填充切面 + * 拦截标注了 @AutoFillDictTags 注解的方法或类,自动查询并填充字典标签ID + * + * 支持的拦截方式: + * 1. 方法级别:@AutoFillDictTags 标注在具体方法上 + * 2. 类级别:@AutoFillDictTags 标注在类上,拦截该类所有 public 方法 + */ +@Slf4j +@Aspect +@Component +@Order(1) // 设置较高优先级,确保在业务逻辑执行前处理 +public class DictTagsAutoFillAspect { + + @Resource + private DictTagHelper dictTagHelper; + + /** + * 前置通知:在方法执行前自动填充字典标签 + * 支持两种拦截方式: + * 1. 方法级别:@annotation(autoFillDictTags) - 拦截标注了 @AutoFillDictTags 的方法 + * 2. 类级别:@within(com.sdm.common.annotation.AutoFillDictTags) - 拦截标注了 @AutoFillDictTags 的类中的所有 public 方法 + */ + @Before("@annotation(autoFillDictTags) || @within(com.sdm.common.annotation.AutoFillDictTags)") + public void autoFillDictTags(JoinPoint joinPoint, AutoFillDictTags autoFillDictTags) { + try { + // 如果是类级别注解,autoFillDictTags 为 null,需要从类上获取 + if (autoFillDictTags == null) { + Class targetClass = joinPoint.getTarget().getClass(); + autoFillDictTags = targetClass.getAnnotation(AutoFillDictTags.class); + } + + // 如果仍然为 null,说明注解在接口上,使用默认配置 + final boolean ignoreEmpty = autoFillDictTags != null ? autoFillDictTags.ignoreEmpty() : true; + final Set targetParamNames = new HashSet<>(); + if (autoFillDictTags != null && autoFillDictTags.paramNames().length > 0) { + targetParamNames.addAll(Arrays.asList(autoFillDictTags.paramNames())); + } + + Object[] args = joinPoint.getArgs(); + if (args == null || args.length == 0) { + return; + } + + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + String[] parameterNames = signature.getParameterNames(); + + // 遍历所有参数 + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + if (arg == null) { + continue; + } + + String paramName = i < parameterNames.length ? parameterNames[i] : "arg" + i; + + // 如果指定了参数名称,检查是否匹配 + if (!targetParamNames.isEmpty() && !targetParamNames.contains(paramName)) { + continue; + } + + // 检查参数是否包含dictTags字段 + if (!hasDictTagsField(arg)) { + continue; + } + + // 如果设置了ignoreEmpty,检查dictTags是否为空 + if (ignoreEmpty && isDictTagsEmpty(arg)) { + continue; + } + + // 执行自动填充 + try { + dictTagHelper.queryAndCacheDictTagIds(arg); + log.debug("Auto-filled dict tags for parameter '{}' in method {}.{}", + paramName, + method.getDeclaringClass().getSimpleName(), + method.getName()); + } catch (Exception e) { + log.warn("Failed to auto-fill dict tags for parameter '{}': {}", + paramName, e.getMessage()); + // 继续执行,不影响主流程 + } + } + } catch (Exception e) { + log.error("Error in DictTagsAutoFillAspect: {}", e.getMessage(), e); + // 即使切面出错,也不影响主流程 + } + } + + /** + * 检查对象是否包含dictTags字段 + */ + private boolean hasDictTagsField(Object obj) { + try { + Field field = findField(obj.getClass(), "dictTags"); + return field != null; + } catch (Exception e) { + return false; + } + } + + /** + * 检查dictTags是否为空 + */ + private boolean isDictTagsEmpty(Object obj) { + try { + Field field = findField(obj.getClass(), "dictTags"); + if (field == null) { + return true; + } + field.setAccessible(true); + Object value = field.get(obj); + + if (value == null) { + return true; + } + + if (value instanceof List) { + return ((List) value).isEmpty(); + } + + return false; + } catch (Exception e) { + return true; + } + } + + /** + * 在类及其父类中查找字段 + */ + private Field findField(Class clazz, String fieldName) { + while (clazz != null && clazz != Object.class) { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + clazz = clazz.getSuperclass(); + } + } + return null; + } +} diff --git a/common/src/main/java/com/sdm/common/entity/bo/DataDictionary.java b/common/src/main/java/com/sdm/common/entity/bo/DataDictionary.java index 5b2a951e..c5d0b8af 100644 --- a/common/src/main/java/com/sdm/common/entity/bo/DataDictionary.java +++ b/common/src/main/java/com/sdm/common/entity/bo/DataDictionary.java @@ -8,7 +8,7 @@ public class DataDictionary extends BaseBean { { init(); } - public int id; + public Integer id; public String uuid; public String dictName; public String dictValue; diff --git a/common/src/main/java/com/sdm/common/entity/req/data/GetSimulationTaskFileReq.java b/common/src/main/java/com/sdm/common/entity/req/data/GetSimulationTaskFileReq.java index 4d6b725f..c7f2dca9 100644 --- a/common/src/main/java/com/sdm/common/entity/req/data/GetSimulationTaskFileReq.java +++ b/common/src/main/java/com/sdm/common/entity/req/data/GetSimulationTaskFileReq.java @@ -1,12 +1,15 @@ package com.sdm.common.entity.req.data; +import com.alibaba.fastjson2.annotation.JSONField; import com.fasterxml.jackson.annotation.JsonFormat; import com.sdm.common.entity.enums.FileBizTypeEnum; +import com.sdm.common.entity.req.system.DictTagReq; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; @Data public class GetSimulationTaskFileReq extends BaseReq { @@ -16,6 +19,34 @@ public class GetSimulationTaskFileReq extends BaseReq { @Schema(description = "文件类型", implementation = FileBizTypeEnum.class) Integer fileBizType; + // ---------------------------------------------------------------- + // 很重要,用于设置标签,通过autoFillDictTags切面 ,设置dictTagIdsCache + /** + * 字典标签查询结果缓存 + * key: dictClass(字典类) + * value: Map(字典值 -> 字典ID) + * 此字段由服务层填充,前端不需传入 + */ + @Schema(description = "字典标签查询结果缓存", hidden = true) + @JSONField(serialize = false) + private Map> dictTagIdsCache; + + @Schema(description = "字典标签查询列表,格式:['fileTypeDictClass','fileTypeDictValue','disciplineTypeDictClass','disciplineDictValue']") + private List dictTags; + + @Schema(description = "文件类型字典类") + private String fileTypeDictClass; + @Schema(description = "文件类型字典值") + private String fileTypeDictValue; + + @Schema(description = "学科类型字典类") + private String disciplineTypeDictClass; + + @Schema(description = "学科类型字典值") + private String disciplineDictValue; + + // ---------------------------------------------------------------- + @Schema(description = "文件名") private String fileName; diff --git a/common/src/main/java/com/sdm/common/entity/req/data/UploadFilesReq.java b/common/src/main/java/com/sdm/common/entity/req/data/UploadFilesReq.java index eee1f07e..1078c42f 100644 --- a/common/src/main/java/com/sdm/common/entity/req/data/UploadFilesReq.java +++ b/common/src/main/java/com/sdm/common/entity/req/data/UploadFilesReq.java @@ -8,6 +8,7 @@ import lombok.Data; import org.springframework.web.multipart.MultipartFile; import java.util.List; +import java.util.Map; @Data @Schema(description = "文件上传请求参数") @@ -71,8 +72,33 @@ public class UploadFilesReq { @Schema(description = "文件类型 1:模型文件 2:仿真报告 3:计算文件 4:曲线文件 5:云图文件", implementation = FileBizTypeEnum.class) private Integer fileType; - @Schema(description = "字典标签列表") - private List tags; + // ---------------------------------------------------------------- + // 很重要,用于设置标签,通过autoFillDictTags切面 ,设置dictTagIdsCache + /** + * 字典标签查询结果缓存 + * key: dictClass(字典类) + * value: Map(字典值 -> 字典ID) + * 此字段由服务层填充,前端不需传入 + */ + @Schema(description = "字典标签查询结果缓存", hidden = true) + @JSONField(serialize = false) + private Map> dictTagIdsCache; + + @Schema(description = "字典标签查询列表,格式:['fileTypeDictClass','fileTypeDictValue','disciplineTypeDictClass','disciplineDictValue']") + private List dictTags; + + @Schema(description = "文件类型字典类") + private String fileTypeDictClass; + @Schema(description = "文件类型字典值") + private String fileTypeDictValue; + + @Schema(description = "学科类型字典类") + private String disciplineTypeDictClass; + + @Schema(description = "学科类型字典值") + private String disciplineDictValue; + + // ---------------------------------------------------------------- /** diff --git a/common/src/main/java/com/sdm/common/entity/req/export/FileAnalysisExportExcelParam.java b/common/src/main/java/com/sdm/common/entity/req/export/FileAnalysisExportExcelParam.java index e3bdf6e3..ad1f8702 100644 --- a/common/src/main/java/com/sdm/common/entity/req/export/FileAnalysisExportExcelParam.java +++ b/common/src/main/java/com/sdm/common/entity/req/export/FileAnalysisExportExcelParam.java @@ -1,13 +1,16 @@ package com.sdm.common.entity.req.export; +import com.alibaba.fastjson2.annotation.JSONField; import com.fasterxml.jackson.annotation.JsonFormat; import com.sdm.common.entity.enums.FileBizTypeEnum; import com.sdm.common.entity.req.data.BaseReq; +import com.sdm.common.entity.req.system.DictTagReq; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; @Data public class FileAnalysisExportExcelParam extends BaseReq { @@ -18,6 +21,34 @@ public class FileAnalysisExportExcelParam extends BaseReq { @Schema(description = "文件类型", implementation = FileBizTypeEnum.class) Integer fileBizType; + // ---------------------------------------------------------------- + // 很重要,用于设置标签,通过autoFillDictTags切面 ,设置dictTagIdsCache + /** + * 字典标签查询结果缓存 + * key: dictClass(字典类) + * value: Map(字典值 -> 字典ID) + * 此字段由服务层填充,前端不需传入 + */ + @Schema(description = "字典标签查询结果缓存", hidden = true) + @JSONField(serialize = false) + private Map> dictTagIdsCache; + + @Schema(description = "字典标签查询列表,格式:['fileTypeDictClass','fileTypeDictValue','disciplineTypeDictClass','disciplineDictValue']") + private List dictTags; + + @Schema(description = "文件类型字典类") + private String fileTypeDictClass; + @Schema(description = "文件类型字典值") + private String fileTypeDictValue; + + @Schema(description = "学科类型字典类") + private String disciplineTypeDictClass; + + @Schema(description = "学科类型字典值") + private String disciplineDictValue; + + // ---------------------------------------------------------------- + @Schema(description = "文件名") private String fileName; diff --git a/common/src/main/java/com/sdm/common/entity/req/system/DictTagReq.java b/common/src/main/java/com/sdm/common/entity/req/system/DictTagReq.java index 60667cb2..1138439b 100644 --- a/common/src/main/java/com/sdm/common/entity/req/system/DictTagReq.java +++ b/common/src/main/java/com/sdm/common/entity/req/system/DictTagReq.java @@ -4,16 +4,23 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; +import java.util.Map; @Data @Schema(description = "字典标签查询请求") public class DictTagReq { + @Schema(description = "字典类型", example = "file_type") + private String dictClass; + @Schema(description = "字典名称", example = "file_type") private String dictName; @Schema(description = "字典值", example = "document") private String dictValue; + @Schema(description = "字典值数组字符串", example = "document") + private String dictValues; + @Data @Schema(description = "批量查询字典ID请求") public static class BatchDictIdQueryReq { diff --git a/common/src/main/java/com/sdm/common/feign/impl/system/SysConfigFeignClientImpl.java b/common/src/main/java/com/sdm/common/feign/impl/system/SysConfigFeignClientImpl.java index 697c301d..cac31e8a 100644 --- a/common/src/main/java/com/sdm/common/feign/impl/system/SysConfigFeignClientImpl.java +++ b/common/src/main/java/com/sdm/common/feign/impl/system/SysConfigFeignClientImpl.java @@ -36,10 +36,10 @@ public class SysConfigFeignClientImpl implements ISysConfigFeignClient { } @Override - public SdmResponse>> batchQueryDictionaryIds(DictTagReq.BatchDictIdQueryReq req) { - SdmResponse>> sdmResponse; + public SdmResponse>> multiQueryDictionaryIds(DictTagReq.BatchDictIdQueryReq req) { + SdmResponse>> sdmResponse; try { - sdmResponse = sysConfigFeignClient.batchQueryDictionaryIds(req); + sdmResponse = sysConfigFeignClient.multiQueryDictionaryIds(req); if(!sdmResponse.isSuccess() ||ObjectUtils.isEmpty(sdmResponse.getData())){ return SdmResponse.failed("字典信息未查询"); } @@ -48,6 +48,5 @@ public class SysConfigFeignClientImpl implements ISysConfigFeignClient { log.error("字典信息失败", e); return SdmResponse.failed("字典信息未查询"); } - } } diff --git a/common/src/main/java/com/sdm/common/feign/inter/system/ISysConfigFeignClient.java b/common/src/main/java/com/sdm/common/feign/inter/system/ISysConfigFeignClient.java index 07447dbe..5de2c45d 100644 --- a/common/src/main/java/com/sdm/common/feign/inter/system/ISysConfigFeignClient.java +++ b/common/src/main/java/com/sdm/common/feign/inter/system/ISysConfigFeignClient.java @@ -18,7 +18,8 @@ public interface ISysConfigFeignClient { @GetMapping(value = "/systemData/getDictionaryData") SdmResponse> getDictionaryData(@RequestParam("dictClass")String dictClass); - @PostMapping(value = "/systemData/batchDictionaryIds") - SdmResponse>> batchQueryDictionaryIds(@RequestBody DictTagReq.BatchDictIdQueryReq req); + + @PostMapping(value = "/systemData/multiDictionaryIds") + SdmResponse>> multiQueryDictionaryIds(@RequestBody DictTagReq.BatchDictIdQueryReq req); } diff --git a/common/src/main/java/com/sdm/common/utils/DictTagHelper.java b/common/src/main/java/com/sdm/common/utils/DictTagHelper.java new file mode 100644 index 00000000..6834d80f --- /dev/null +++ b/common/src/main/java/com/sdm/common/utils/DictTagHelper.java @@ -0,0 +1,192 @@ +package com.sdm.common.utils; + +import com.sdm.common.common.SdmResponse; +import com.sdm.common.entity.req.system.DictTagReq; +import com.sdm.common.feign.inter.system.ISysConfigFeignClient; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 字典标签查询工具类 + * 提供统一的字典标签ID查询功能,避免重复代码 + */ +@Slf4j +@Component +public class DictTagHelper { + + @Resource + private ISysConfigFeignClient sysConfigFeignClient; + + /** + * 从对象中提取字典标签并查询对应的字典ID + * + * @param obj 包含dictTags字段的对象 + * @return Map>,查询失败或无数据返回空Map + */ + public Map> queryDictTagIds(Object obj) { + if (obj == null) { + return new HashMap<>(); + } + + // 获取dictTags字段 + List dictTags = getDictTags(obj); + if (dictTags == null || dictTags.isEmpty()) { + return new HashMap<>(); + } + + // 构造BatchDictIdQueryReq请求 + List tagReqList = buildDictTagReqList(obj, dictTags); + if (tagReqList.isEmpty()) { + return new HashMap<>(); + } + + // 调用接口查询 + return queryDictIds(tagReqList); + } + + /** + * 从对象中提取字典标签并查询,同时将结果缓存到对象的dictTagIdsCache字段 + * + * @param obj 包含dictTags和dictTagIdsCache字段的对象 + * @return Map> + */ + public Map> queryAndCacheDictTagIds(Object obj) { + Map> result = queryDictTagIds(obj); + + // 将结果缓存到对象的dictTagIdsCache字段 + if (!result.isEmpty()) { + setDictTagIdsCache(obj, result); + } + + return result; + } + + /** + * 从对象获取dictTags字段值 + */ + private List getDictTags(Object obj) { + try { + Field field = findField(obj.getClass(), "dictTags"); + if (field == null) { + log.warn("Field 'dictTags' not found in class {}", obj.getClass().getSimpleName()); + return null; + } + field.setAccessible(true); + return (List) field.get(obj); + } catch (Exception e) { + log.error("Failed to get dictTags from object: {}", e.getMessage()); + return null; + } + } + + /** + * 设置对象的dictTagIdsCache字段值 + */ + private void setDictTagIdsCache(Object obj, Map> cache) { + try { + Field field = findField(obj.getClass(), "dictTagIdsCache"); + if (field == null) { + return; + } + field.setAccessible(true); + field.set(obj, cache); + } catch (Exception e) { + log.error("Failed to set dictTagIdsCache to object: {}", e.getMessage()); + } + } + + /** + * 构造DictTagReq列表 + * 从dictTags中每次取两个值:dictClass字段名和dictValue字段名 + * 然后通过反射从obj对象获取对应字段的实际值 + */ + private List buildDictTagReqList(Object obj, List dictTags) { + List tagReqList = new ArrayList<>(); + + for (int i = 0; i < dictTags.size() - 1; i += 2) { + String dictClassFieldName = dictTags.get(i); + String dictValueFieldName = dictTags.get(i + 1); + + // 通过反射获取对象中对应字段的实际值 + String dictClass = getFieldValueAsString(obj, dictClassFieldName); + String dictValues = getFieldValueAsString(obj, dictValueFieldName); + + if (StringUtils.isNotBlank(dictClass) && StringUtils.isNotBlank(dictValues)) { + DictTagReq tagReq = new DictTagReq(); + tagReq.setDictClass(dictClass); + tagReq.setDictValues(dictValues); + tagReqList.add(tagReq); + } + } + + return tagReqList; + } + + /** + * 调用Feign接口查询字典ID + */ + private Map> queryDictIds(List tagReqList) { + DictTagReq.BatchDictIdQueryReq batchReq = new DictTagReq.BatchDictIdQueryReq(); + batchReq.setItems(tagReqList); + + try { + SdmResponse>> response = + sysConfigFeignClient.multiQueryDictionaryIds(batchReq); + + if (response.isSuccess() && response.getData() != null) { + return response.getData(); + } else { + log.warn("Failed to query dictionary ids: {}", response.getMessage()); + return new HashMap<>(); + } + } catch (Exception e) { + log.error("Exception occurred while querying dictionary ids: {}", e.getMessage(), e); + return new HashMap<>(); + } + } + + /** + * 通过反射获取字段值并转换为String + */ + private String getFieldValueAsString(Object obj, String fieldName) { + if (obj == null || StringUtils.isBlank(fieldName)) { + return null; + } + + try { + Field field = findField(obj.getClass(), fieldName); + if (field == null) { + return null; + } + + field.setAccessible(true); + Object value = field.get(obj); + return value != null ? value.toString() : null; + } catch (Exception e) { + log.error("Failed to get field '{}' from object: {}", fieldName, e.getMessage()); + return null; + } + } + + /** + * 在类及其父类中查找字段 + */ + private Field findField(Class clazz, String fieldName) { + while (clazz != null && clazz != Object.class) { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + clazz = clazz.getSuperclass(); + } + } + return null; + } +} diff --git a/data/pom.xml b/data/pom.xml index 0e1982bc..13fc1dad 100644 --- a/data/pom.xml +++ b/data/pom.xml @@ -50,6 +50,12 @@ org.springframework.boot spring-boot-starter-web + + org.projectlombok + lombok + ${lombok.version} + true + commons-net @@ -190,12 +196,6 @@ org.springframework.boot spring-boot-maven-plugin - - - org.projectlombok - lombok - - true diff --git a/data/src/main/java/com/sdm/data/controller/DataAnalysisController.java b/data/src/main/java/com/sdm/data/controller/DataAnalysisController.java index fe93e882..d0b75356 100644 --- a/data/src/main/java/com/sdm/data/controller/DataAnalysisController.java +++ b/data/src/main/java/com/sdm/data/controller/DataAnalysisController.java @@ -1,5 +1,6 @@ package com.sdm.data.controller; +import com.sdm.common.annotation.AutoFillDictTags; import com.sdm.common.common.SdmResponse; import com.sdm.common.entity.req.data.GetSimulationTaskFileReq; import com.sdm.common.entity.req.export.FileAnalysisExportExcelFormat; @@ -33,6 +34,7 @@ public class DataAnalysisController implements IDataAnalysisFeignClient { * 数据分析(数据查询)-获取 simulationtTask的文件 * */ + @AutoFillDictTags @Operation(summary = "获取 simulationtTask的文件,文件类型: 1:模型文件 2:仿真报告 3:计算文件 4:曲线文件 5:云图文件") @PostMapping("/getSimulationTaskFile") public SdmResponse>> getSimulationTaskFile(@RequestBody @Validated GetSimulationTaskFileReq getSimulationTaskFileReq) { @@ -50,6 +52,7 @@ public class DataAnalysisController implements IDataAnalysisFeignClient { return dataAnalysisService.getCSVData(fileId); } + @AutoFillDictTags @PostMapping(value = "/exportTaskFileByScript") @ResponseBody SdmResponse exportTaskFileByScript(HttpServletResponse response , @RequestBody FileAnalysisExportExcelFormat req) { diff --git a/data/src/main/java/com/sdm/data/controller/DataFileController.java b/data/src/main/java/com/sdm/data/controller/DataFileController.java index 50fbb4a3..8550c77e 100644 --- a/data/src/main/java/com/sdm/data/controller/DataFileController.java +++ b/data/src/main/java/com/sdm/data/controller/DataFileController.java @@ -1,5 +1,6 @@ package com.sdm.data.controller; +import com.sdm.common.annotation.AutoFillDictTags; import com.sdm.common.annotation.IgnoreAuth; import com.sdm.common.common.SdmResponse; import com.sdm.common.entity.enums.DirTypeEnum; @@ -138,6 +139,7 @@ public class DataFileController implements IDataFeignClient { * @param req * @return */ + @AutoFillDictTags @PostMapping("/fileSearch") @Operation(summary = "搜索文件", description = "根据搜索条件查找匹配的文件") public SdmResponse fileSearch(@RequestBody @Validated FileSearchReq req) { @@ -349,6 +351,7 @@ public class DataFileController implements IDataFeignClient { * @param req * @return */ + @AutoFillDictTags @SysLog("上传文件") @PostMapping(value = "/uploadFiles", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @Operation( @@ -494,6 +497,7 @@ public class DataFileController implements IDataFeignClient { /** * 文件信息入库准备发起评审 */ + @AutoFillDictTags @SysLog("新增文件") @PostMapping("/batchAddFileInfo") @Operation(summary = "文件信息入库准备发起评审") diff --git a/data/src/main/java/com/sdm/data/controller/DataOverviewController.java b/data/src/main/java/com/sdm/data/controller/DataOverviewController.java index f500c025..bafee17d 100644 --- a/data/src/main/java/com/sdm/data/controller/DataOverviewController.java +++ b/data/src/main/java/com/sdm/data/controller/DataOverviewController.java @@ -1,6 +1,7 @@ package com.sdm.data.controller; +import com.sdm.common.annotation.AutoFillDictTags; import com.sdm.common.common.SdmResponse; import com.sdm.common.entity.req.data.CreateDirReq; import com.sdm.common.entity.req.data.UploadFilesReq; @@ -86,6 +87,7 @@ public class DataOverviewController { /** * 搜索项目节点下的文件 */ + @AutoFillDictTags @PostMapping("/searchSimulationNodeFiles") @Operation(summary = "搜索项目节点下的文件") public SdmResponse searchSimulationNodeFiles(@RequestBody FileSearchReq req) { diff --git a/data/src/main/java/com/sdm/data/controller/DataStorageAnalysisController.java b/data/src/main/java/com/sdm/data/controller/DataStorageAnalysisController.java index 6e6c68f0..8c74590a 100644 --- a/data/src/main/java/com/sdm/data/controller/DataStorageAnalysisController.java +++ b/data/src/main/java/com/sdm/data/controller/DataStorageAnalysisController.java @@ -3,6 +3,7 @@ package com.sdm.data.controller; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.sdm.common.annotation.AutoFillDictTags; import com.sdm.common.common.SdmResponse; import com.sdm.common.common.ThreadLocalContext; import com.sdm.common.entity.req.project.GetAllTasksByDisciplineReq; @@ -119,6 +120,7 @@ public class DataStorageAnalysisController { } // 存储系统大文件筛选 + @AutoFillDictTags @PostMapping("/listBigFile") @Operation(summary = "存储系统大文件筛选") public SdmResponse>> listBigFile(@RequestBody QueryBigFileReq queryBigFileReq){ diff --git a/data/src/main/java/com/sdm/data/model/req/FileSearchReq.java b/data/src/main/java/com/sdm/data/model/req/FileSearchReq.java index ada0c867..f356b118 100644 --- a/data/src/main/java/com/sdm/data/model/req/FileSearchReq.java +++ b/data/src/main/java/com/sdm/data/model/req/FileSearchReq.java @@ -1,12 +1,15 @@ package com.sdm.data.model.req; +import com.alibaba.fastjson2.annotation.JSONField; import com.sdm.common.entity.req.data.BaseReq; +import com.sdm.common.entity.req.system.DictTagReq; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Map; @Data @Schema(description = "文件搜索请求参数") @@ -86,6 +89,34 @@ public class FileSearchReq extends BaseReq { @Schema(description = "文件业务类型(1:模型文件 2:仿真报告、3:计算文件、4:曲线文件、5:云图文件,6:网格文件,7:计算过程文件)",enumAsRef = true) private List fileBizType; + // ---------------------------------------------------------------- + // 很重要,用于设置标签,通过autoFillDictTags切面 ,设置dictTagIdsCache + /** + * 字典标签查询结果缓存 + * key: dictClass(字典类) + * value: Map(字典值 -> 字典ID) + * 此字段由服务层填充,前端不需传入 + */ + @Schema(description = "字典标签查询结果缓存", hidden = true) + @JSONField(serialize = false) + private Map> dictTagIdsCache; + + @Schema(description = "字典标签查询列表,格式:['fileTypeDictClass','fileTypeDictValue','disciplineTypeDictClass','disciplineDictValue']") + private List dictTags; + + @Schema(description = "文件类型字典类") + private String fileTypeDictClass; + @Schema(description = "文件类型字典值") + private String fileTypeDictValue; + + @Schema(description = "学科类型字典类") + private String disciplineTypeDictClass; + + @Schema(description = "学科类型字典值") + private String disciplineDictValue; + + // ---------------------------------------------------------------- + /** * 是否过滤空数据 */ diff --git a/data/src/main/java/com/sdm/data/model/req/QueryBigFileReq.java b/data/src/main/java/com/sdm/data/model/req/QueryBigFileReq.java index 634e5220..b3b3870a 100644 --- a/data/src/main/java/com/sdm/data/model/req/QueryBigFileReq.java +++ b/data/src/main/java/com/sdm/data/model/req/QueryBigFileReq.java @@ -1,13 +1,16 @@ package com.sdm.data.model.req; +import com.alibaba.fastjson2.annotation.JSONField; import com.fasterxml.jackson.annotation.JsonFormat; import com.sdm.common.entity.req.data.BaseReq; +import com.sdm.common.entity.req.system.DictTagReq; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Map; @Data public class QueryBigFileReq extends BaseReq { @@ -64,13 +67,49 @@ public class QueryBigFileReq extends BaseReq { @Schema(description = "文件业务类型(1:模型文件 2:仿真报告、3:计算文件、4:曲线文件、5:云图文件,6:网格文件,7:计算过程文件)") private List fileBizType; - @Schema(description = "上传人id") - private List uploadUserId; + // ---------------------------------------------------------------- + // 很重要,用于设置标签,通过autoFillDictTags切面 ,设置dictTagIdsCache + /** + * 字典标签查询结果缓存 + * key: dictClass(字典类) + * value: Map(字典值 -> 字典ID) + * 此字段由服务层填充,前端不需传入 + */ + @Schema(description = "字典标签查询结果缓存", hidden = true) + @JSONField(serialize = false) + private Map> dictTagIdsCache; + @Schema(description = "字典标签查询列表,格式:['fileTypeDictClass','fileTypeDictValue','disciplineTypeDictClass','disciplineDictValue']") + private List dictTags; + + @Schema(description = "文件类型字典类") + private String fileTypeDictClass; + @Schema(description = "文件类型字典值") + private String fileTypeDictValue; + + @Schema(description = "学科类型字典类") + private String disciplineTypeDictClass; + + @Schema(description = "学科类型字典值") + private String disciplineDictValue; + + // ---------------------------------------------------------------- + + @Schema(description = "上传人 id") + private List uploadUserId; + @Schema(description = "审批类型") private List approveTypeList; - + @Schema(description = "是否最新") Boolean isLatest=true; + + /** + * 通过标签查询到的文件ID列表 + * 此字段由服务层填充,用于标签筛选 + */ + @Schema(description = "通过标签查询到的文件ID列表", hidden = true) + @JSONField(serialize = false) + private List fileIds; } diff --git a/data/src/main/java/com/sdm/data/service/impl/DataAnalysisServiceImpl.java b/data/src/main/java/com/sdm/data/service/impl/DataAnalysisServiceImpl.java index 7191aa06..d415173c 100644 --- a/data/src/main/java/com/sdm/data/service/impl/DataAnalysisServiceImpl.java +++ b/data/src/main/java/com/sdm/data/service/impl/DataAnalysisServiceImpl.java @@ -65,7 +65,6 @@ public class DataAnalysisServiceImpl implements IDataAnalysisService { // 1. 构造查询条件 QueryBigFileReq queryBigFileReq = new QueryBigFileReq(); BeanUtils.copyProperties(getSimulationTaskFileReq, queryBigFileReq); - queryBigFileReq.setFileBizType(List.of(getSimulationTaskFileReq.getFileBizType())); // 获取特定 UUID 对应的目录 ID if (ObjectUtils.isNotEmpty(getSimulationTaskFileReq.getUuid())) { diff --git a/data/src/main/java/com/sdm/data/service/impl/DataStorageAnalysisImpl.java b/data/src/main/java/com/sdm/data/service/impl/DataStorageAnalysisImpl.java index 7dbd5ba0..80c4d643 100644 --- a/data/src/main/java/com/sdm/data/service/impl/DataStorageAnalysisImpl.java +++ b/data/src/main/java/com/sdm/data/service/impl/DataStorageAnalysisImpl.java @@ -7,10 +7,13 @@ import com.github.pagehelper.PageInfo; import com.sdm.common.common.SdmResponse; import com.sdm.common.common.ThreadLocalContext; import com.sdm.common.entity.enums.ApproveFileDataTypeEnum; +import com.sdm.common.entity.req.system.DictTagReq; import com.sdm.common.entity.req.system.UserListReq; import com.sdm.common.entity.resp.PageDataResp; import com.sdm.common.entity.resp.system.CIDUserResp; +import com.sdm.common.feign.impl.system.SysConfigFeignClientImpl; import com.sdm.common.feign.impl.system.SysUserFeignClientImpl; +import com.sdm.common.feign.inter.system.ISysConfigFeignClient; import com.sdm.common.service.UserNameCacheService; import com.sdm.common.utils.FileSizeUtils; import com.sdm.common.utils.PageUtils; @@ -19,6 +22,7 @@ import com.sdm.data.model.dto.UserTotalFileSizeDTO; import com.sdm.data.model.entity.FileMetadataInfo; import com.sdm.data.model.entity.FileStorage; import com.sdm.data.model.entity.FileStorageQuota; +import com.sdm.data.model.entity.FileTagRel; import com.sdm.data.model.enums.FileStorageQuotaStatusEnum; import com.sdm.data.model.req.AddUserQuotaEntity; import com.sdm.common.entity.req.data.DelFileReq; @@ -54,6 +58,9 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis { @Autowired SysUserFeignClientImpl sysUserFeignClient; + @Autowired + ISysConfigFeignClient sysConfigFeignClient; + @Autowired UserNameCacheService userNameCacheService; @@ -67,6 +74,9 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis { @Autowired FileMetadataHierarchyHelper hierarchyHelper; + @Autowired + IFileTagRelService fileTagRelService; + /** * 根据节点类型获取存储空间占用(支持批量查询) */ @@ -456,6 +466,15 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis { if(ObjectUtils.isNotEmpty((queryBigFileReq.getDirId()))){ queryBigFileReq.getDirIds().add(queryBigFileReq.getDirId()); } + + // 处理标签查询(使用AOP自动填充的dictTagIdsCache) + if (queryBigFileReq.getDictTags() != null && !queryBigFileReq.getDictTags().isEmpty()) { + List fileIds = extractFileIdsByTags(queryBigFileReq); + if (fileIds != null) { + queryBigFileReq.setFileIds(fileIds); + } + } + Long tenantId = ThreadLocalContext.getTenantId(); PageHelper.startPage(queryBigFileReq.getCurrent(), queryBigFileReq.getSize()); List list = fileStorageService.selectBigFiles(queryBigFileReq, fileSizeInBytes, tenantId); @@ -490,6 +509,47 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis { } } + /** + * 从缓存的字典标签ID中提取文件ID列表 + * 此方法直接使用AOP切面自动填充的dictTagIdsCache,无需再次查询字典 + * + * @param queryBigFileReq 查询请求对象(已由AOP填充dictTagIdsCache) + * @return 匹配的文件ID列表,如果没有匹配项则返回null + */ + private List extractFileIdsByTags(QueryBigFileReq queryBigFileReq) { + // 使用AOP自动填充的dictTagIdsCache + Map> dictIdMap = queryBigFileReq.getDictTagIdsCache(); + if (dictIdMap == null || dictIdMap.isEmpty()) { + log.warn("Dict tags cache is empty, cannot extract file ids by tags"); + return null; + } + + // 收集所有字典ID + Set tagIds = new HashSet<>(); + for (Map valueMap : dictIdMap.values()) { + tagIds.addAll(valueMap.values()); + } + + if (CollectionUtils.isEmpty(tagIds)) { + return null; + } + + Long tenantId = ThreadLocalContext.getTenantId(); + List dirIds = CollectionUtils.isEmpty(queryBigFileReq.getDirIds()) ? null : queryBigFileReq.getDirIds(); + + // 查询符合标签的文件id + return fileTagRelService.lambdaQuery() + .eq(FileTagRel::getTenantId, tenantId) + .in(dirIds != null, FileTagRel::getDirId, dirIds) + .in(FileTagRel::getTagId, tagIds) + .select(FileTagRel::getFileId) + .list() + .stream() + .map(FileTagRel::getFileId) + .distinct() + .collect(Collectors.toList()); + } + @Override public SdmResponse batchDeleteBigFile(List fileIds) { if (CollectionUtils.isEmpty(fileIds)) { diff --git a/data/src/main/java/com/sdm/data/service/impl/MinioFileIDataFileServiceImpl.java b/data/src/main/java/com/sdm/data/service/impl/MinioFileIDataFileServiceImpl.java index d9138188..0487884d 100644 --- a/data/src/main/java/com/sdm/data/service/impl/MinioFileIDataFileServiceImpl.java +++ b/data/src/main/java/com/sdm/data/service/impl/MinioFileIDataFileServiceImpl.java @@ -76,6 +76,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; import java.math.BigDecimal; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -166,6 +167,9 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { @Autowired private LocalFileService localFileService; + + @Autowired + private DictTagHelper dictTagHelper; @@ -374,7 +378,6 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { * * @param filePath 文件路径 * @param fileName 文件名 - * @param fileType 文件类型 * @param projectId 项目ID * @param analysisDirectionId 分析方向ID * @param remarks 备注信息 @@ -382,8 +385,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { * @param fileSize 文件大小 * @return 创建后的文件元数据信息 */ - private FileMetadataInfo createFileMetadata(String filePath, String fileName, Integer fileType - , String projectId, String analysisDirectionId, String remarks, Long parentId, Long fileSize + private FileMetadataInfo createFileMetadata(String filePath, String fileName, String projectId, String analysisDirectionId, String remarks, Long parentId, Long fileSize ) { FileMetadataInfo fileInfo = new FileMetadataInfo(); fileInfo.setObjectKey(filePath); @@ -393,7 +395,6 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { fileInfo.setAnalysisDirectionId(analysisDirectionId); fileInfo.setRemarks(remarks); fileInfo.setDataType(DataTypeEnum.FILE.getValue()); - fileInfo.setFileType(fileType); fileInfo.setParentId(parentId); fileInfo.setIsRoot(false); fileInfo.setCreatorId(ThreadLocalContext.getUserId()); @@ -1442,7 +1443,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { try { minioService.copyFile(oldDirMinioObjectKey, newDirMinioObjectKey,sourceMetadataInfo.getBucketName()); // 创建目录元数据并保存到数据库 - FileMetadataInfo fileInfo = createFileMetadata(newDirMinioObjectKey, sourceMetadataInfo.getOriginalName(), sourceMetadataInfo.getFileType(), + FileMetadataInfo fileInfo = createFileMetadata(newDirMinioObjectKey, sourceMetadataInfo.getOriginalName(), null, null, null, targetParentMetadataInfo.getId(), sourceMetadataInfo.getFileSize()); fileMetadataInfoService.save(fileInfo); return SdmResponse.success("复制文件成功"); @@ -1787,7 +1788,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { try { minioService.uploadFile(req.getFile(), fileMinioObjectKey, null, dirMetadataInfo.getBucketName()); - FileMetadataInfo fileInfo = createFileMetadata(fileMinioObjectKey, originalName, req.getFileType(), + FileMetadataInfo fileInfo = createFileMetadata(fileMinioObjectKey, originalName, req.getProjectId(), req.getAnalysisDirectionId(), req.getRemarks(), dirMetadataInfo.getId(), req.getFile().getSize() ); fileMetadataInfoService.save(fileInfo); @@ -1826,7 +1827,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { } try { - FileMetadataInfo fileInfo = createFileMetadata(fileMinioObjectKey, fileReq.getFileName(), fileReq.getFileType(), + FileMetadataInfo fileInfo = createFileMetadata(fileMinioObjectKey, fileReq.getFileName(), req.getProjectId(), req.getAnalysisDirectionId(), req.getRemarks(), dirMetadataInfo.getId(), fileReq.getSize()); fileInfo.setUploadTaskId(req.getUploadTaskId()); fileInfo.setTemplateId(req.getTemplateId()); @@ -1972,8 +1973,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { private void saveFileTags(UploadFilesReq req, FileMetadataInfo fileInfo, FileMetadataInfo dirMetadataInfo, List ancestorDirIds) { - List tags = req.getTags(); - if (CollectionUtils.isEmpty(tags)) { + if (CollectionUtils.isEmpty(req.getDictTags())) { return; } @@ -1981,49 +1981,52 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { Long creatorId = ThreadLocalContext.getUserId(); long fileSize = resolveFileSize(req); - DictTagReq.BatchDictIdQueryReq batchReq = new DictTagReq.BatchDictIdQueryReq(); - batchReq.setItems(tags); - - SdmResponse>> response = sysConfigFeignClient.batchQueryDictionaryIds(batchReq); - if (!response.isSuccess() || response.getData() == null) { - log.warn("Failed to query dictionary ids for tags"); - return; + // 从缓存获取字典标签ID(已由AOP切面自动填充) + Map> dictIdMap = req.getDictTagIdsCache(); + if (dictIdMap == null || dictIdMap.isEmpty()) { + // 如果缓存为空,尝试手动查询(兼容性处理) + log.warn("Dict tags cache is empty, trying to query manually"); + dictIdMap = dictTagHelper.queryAndCacheDictTagIds(req); + if (dictIdMap.isEmpty()) { + log.warn("No dictionary ids found for tags"); + return; + } } - Map> dictIdMap = response.getData(); List directRelList = new ArrayList<>(); List derivedRelList = new ArrayList<>(); - for (DictTagReq tag : tags) { - Map valueMap = dictIdMap.get(tag.getDictName()); - if (valueMap == null || valueMap.get(tag.getDictValue()) == null) { - log.warn("Dictionary not found for dictName: {}, dictValue: {}", tag.getDictName(), tag.getDictValue()); - continue; - } + // 遍历查询结果,构造文件标签关系 + for (Map.Entry> classEntry : dictIdMap.entrySet()) { + Map valueMap = classEntry.getValue(); + + // 遍历该dictClass下的所有dictValue + for (Integer dictId : valueMap.values()) { + if (dictId == null) { + continue; + } - Integer dictId = valueMap.get(tag.getDictValue()); - if (dictId == null) { - continue; - } + // 创建当前目录的直接关联 + FileTagRel directRel = new FileTagRel(); + directRel.setFileId(fileInfo.getId()); + directRel.setTagId(dictId); + directRel.setDirId(dirMetadataInfo.getId()); + directRel.setTenantId(tenantId); + directRel.setCreatorId(creatorId); + directRel.setFileSize(fileSize); + directRelList.add(directRel); - FileTagRel directRel = new FileTagRel(); - directRel.setFileId(fileInfo.getId()); - directRel.setTagId(dictId); - directRel.setDirId(dirMetadataInfo.getId()); - directRel.setTenantId(tenantId); - directRel.setCreatorId(creatorId); - directRel.setFileSize(fileSize); - directRelList.add(directRel); - - for (Long dirIdItem : ancestorDirIds) { - FileTagRel derivedRel = new FileTagRel(); - derivedRel.setFileId(fileInfo.getId()); - derivedRel.setTagId(dictId); - derivedRel.setDirId(dirIdItem); - derivedRel.setTenantId(tenantId); - derivedRel.setCreatorId(creatorId); - derivedRel.setFileSize(fileSize); - derivedRelList.add(derivedRel); + // 创建祖先目录的派生关联 + for (Long dirIdItem : ancestorDirIds) { + FileTagRel derivedRel = new FileTagRel(); + derivedRel.setFileId(fileInfo.getId()); + derivedRel.setTagId(dictId); + derivedRel.setDirId(dirIdItem); + derivedRel.setTenantId(tenantId); + derivedRel.setCreatorId(creatorId); + derivedRel.setFileSize(fileSize); + derivedRelList.add(derivedRel); + } } } @@ -2315,7 +2318,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { minioService.uploadFile(req.getFile(), newFileMinioObjectKey, null,oldFileMetadataInfo.getBucketName()); // 创建目录元数据并保存到数据库 - FileMetadataInfo newFileInfo = createFileMetadata(newFileMinioObjectKey, req.getFileName(), req.getFileType(), + FileMetadataInfo newFileInfo = createFileMetadata(newFileMinioObjectKey, req.getFileName(), req.getProjectId(), req.getAnalysisDirectionId(), req.getRemarks(), oldFileMetadataInfo.getParentId(), req.getFile().getSize() ); newFileInfo.setFileGroupId(fileGroupId); @@ -2470,7 +2473,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { minioService.uploadFile(avatar, avatarMinioObjectKey, null,avatarDirMetadataInfo.getBucketName()); // 创建目录元数据并保存到数据库 - FileMetadataInfo fileInfo = createFileMetadata(avatarMinioObjectKey, newFilename, null, + FileMetadataInfo fileInfo = createFileMetadata(avatarMinioObjectKey, newFilename, null, null, null, parAvatarDirId, avatar.getSize()); fileMetadataInfoService.save(fileInfo); JSONObject jsonObject = new JSONObject(); @@ -2531,7 +2534,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { minioService.uploadFile(paramFile, simulationParamMinioObjectKey, null,simulationParamDirMetadataInfo.getBucketName()); // 创建目录元数据并保存到数据库 - FileMetadataInfo fileInfo = createFileMetadata(simulationParamMinioObjectKey, originalFilename, null, + FileMetadataInfo fileInfo = createFileMetadata(simulationParamMinioObjectKey, originalFilename, null, null, null, parSimulationParamDirId, paramFile.getSize()); // 设置文件状态为审批中 暂不可见 fileInfo.setApprovalStatus(ApprovalFileDataStatusEnum.PENDING.getKey()); @@ -2627,7 +2630,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { minioService.uploadFile(trainModelFile, trainingMinioObjectKey, null,trainModelDirMetadataInfo.getBucketName()); // 创建目录元数据并保存到数据库 - FileMetadataInfo fileInfo = createFileMetadata(trainingMinioObjectKey, originalFilename, null, + FileMetadataInfo fileInfo = createFileMetadata(trainingMinioObjectKey, originalFilename, null, null, null, parTrainModelDirId, trainModelFile.getSize()); fileMetadataInfoService.save(fileInfo); return SdmResponse.success(fileInfo.getId()); @@ -2672,7 +2675,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService { minioService.uploadFile(file, fileMinioObjectKey, null,dirMetadataInfo.getBucketName()); // 创建目录元数据并保存到数据库 - FileMetadataInfo fileInfo = createFileMetadata(fileMinioObjectKey, originalFilename, null, + FileMetadataInfo fileInfo = createFileMetadata(fileMinioObjectKey, originalFilename, null, null, null, parDirId, file.getSize()); fileMetadataInfoService.save(fileInfo); return SdmResponse.success(fileInfo.getId()); diff --git a/data/src/main/resources/mapper/FileStorageMapper.xml b/data/src/main/resources/mapper/FileStorageMapper.xml index 9070494c..e8d4fab9 100644 --- a/data/src/main/resources/mapper/FileStorageMapper.xml +++ b/data/src/main/resources/mapper/FileStorageMapper.xml @@ -158,7 +158,7 @@