From f97d006405d03fac7d84bcaf1c3f4faaad488e5d Mon Sep 17 00:00:00 2001 From: chenchuchuan <13554600537@163.com> Date: Mon, 2 Nov 2026 16:07:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(online-file):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=8C=89=E8=A1=A8=E5=90=8D=E5=85=A8=E9=87=8F=E6=9B=BF=E6=8D=A2?= =?UTF-8?q?=E9=99=84=E4=BB=B6=E5=AD=97=E6=AE=B5=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 OnlineFileService 接口新增 replaceFileListByTableName 方法定义 - 实现按物理表名查询 OnlineTable 并逐字段替换附件数据 - 支持 JSONArray、Collection、单文件对象、JSON 字符串等多种输入格式 - 解析失败时保留旧附件,空数组时清空该字段附件 - 兼容缺少 name 字段时自动使用 filename 作为回退值 - 添加 @Slf4j 日志和 @Transactional 事务注解 - pom.xml 新增 common-core 依赖并将版本升级至 1.0.5.1 --- common/common-online/pom.xml | 7 +- .../common/online/service/OnlineFileService.java | 13 +++ .../online/service/impl/OnlineFileServiceImpl.java | 128 ++++++++++++++++++++- 3 files changed, 143 insertions(+), 5 deletions(-) diff --git a/common/common-online/pom.xml b/common/common-online/pom.xml index 6ada059..d1f1139 100644 --- a/common/common-online/pom.xml +++ b/common/common-online/pom.xml @@ -10,13 +10,18 @@ 4.0.0 common-online - 1.0.5 + 1.0.5.1 common-online jar apelet + common-core + 1.0.1 + + + apelet common-dbutil 1.0.0 diff --git a/common/common-online/src/main/java/apelet/common/online/service/OnlineFileService.java b/common/common-online/src/main/java/apelet/common/online/service/OnlineFileService.java index e37c2db..d3a753a 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/OnlineFileService.java +++ b/common/common-online/src/main/java/apelet/common/online/service/OnlineFileService.java @@ -1,6 +1,7 @@ package apelet.common.online.service; import apelet.common.online.model.OnlineFile; +import com.alibaba.fastjson.JSONObject; import java.util.List; import java.util.Map; @@ -51,4 +52,16 @@ public interface OnlineFileService { */ Map> getOnlineFileMapByBusinessIds( Long onlineTableId, String fieldName, List businessIdList); + + /** + * 按表名和业务Id全量替换附件字段:key为字段名,value为该字段的文件JSON数组。 + *

只处理入参中出现且能解析出文件数组的字段,其它字段的附件数据保持不动; + * value 整体解析失败时该字段按"保留旧附件"处理,空数组则清空该字段附件。

+ * + * @param tableName 物理表名称(zz_online_table.table_name),分录字段传分录表自己的表名。 + * @param businessId 业务Id(所在表记录主键值)。 + * @param fileData key为字段名,value为文件JSON数组。 + */ + void replaceFileListByTableName(String tableName, Long businessId, JSONObject fileData); + } diff --git a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFileServiceImpl.java b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFileServiceImpl.java index 9f19f8b..046e8c0 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFileServiceImpl.java +++ b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFileServiceImpl.java @@ -2,21 +2,28 @@ package apelet.common.online.service.impl; import apelet.common.core.annotation.MyDataSourceResolver; import apelet.common.core.constant.ApplicationConstant; +import apelet.common.core.object.TokenData; import apelet.common.core.util.DefaultDataSourceResolver; import apelet.common.online.dao.OnlineFileMapper; import apelet.common.online.model.OnlineFile; +import apelet.common.online.model.OnlineTable; import apelet.common.online.service.OnlineFileService; +import apelet.common.online.service.OnlineTableService; import apelet.common.sequence.wrapper.IdGeneratorWrapper; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -25,6 +32,7 @@ import java.util.stream.Collectors; * @author guifc * @date 2023-08-04 */ +@Slf4j @MyDataSourceResolver( resolver = DefaultDataSourceResolver.class, intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE) @@ -34,6 +42,8 @@ public class OnlineFileServiceImpl implements OnlineFileService { @Autowired private OnlineFileMapper onlineFileMapper; @Autowired + private OnlineTableService onlineTableService; + @Autowired private IdGeneratorWrapper idGenerator; @Transactional(rollbackFor = Exception.class) @@ -90,4 +100,114 @@ public class OnlineFileServiceImpl implements OnlineFileService { .in("business_id", businessIdList)); return fileList.stream().collect(Collectors.groupingBy(OnlineFile::getBusinessId)); } + + @Transactional(rollbackFor = Exception.class) + @Override + public void replaceFileListByTableName(String tableName, Long businessId, JSONObject fileData) { + if (StrUtil.isBlank(tableName) || businessId == null || MapUtil.isEmpty(fileData)) { + return; + } + OnlineTable table = onlineTableService.getOne(new LambdaQueryWrapper().eq(OnlineTable::getTableName, tableName), false); + if (table == null) { + log.warn("附件替换失败,表 [{}] 未登记到 zz_online_table", tableName); + return; + } + TokenData tokenData = TokenData.takeFromRequest(); + Long operatorUserId = tokenData == null ? null : tokenData.getUserId(); + for (String fieldName : fileData.keySet()) { + List fileList = this.parseOnlineFileList(fileData.get(fieldName), fieldName, operatorUserId); + // 解析失败返回null,按保留旧附件处理;空数组则清空该字段附件。 + if (fileList == null) { + continue; + } + this.replaceFileList(table.getTableId(), fieldName, businessId, fileList); + } + } + + /** + * 把文件字段的JSON数组解析为 OnlineFile 列表。 + *

值为空、不是数组或数组内没有任何可用文件时返回null,交由调用方按"保留旧附件"处理。

+ */ + private List parseOnlineFileList(Object fileValue, String fieldName, Long operatorUserId) { + JSONArray fileArray = this.toJsonArray(fileValue); + if (fileArray == null) { + log.warn("文件字段 [{}] 的数据无法解析为JSON数组,保留原有附件", fieldName); + return null; + } + List fileList = new LinkedList<>(); + for (int i = 0; i < fileArray.size(); i++) { + JSONObject fileItem = this.toJsonObject(fileArray.get(i)); + if (fileItem == null) { + continue; + } + String fileName = fileItem.getString("filename"); + if (StrUtil.isBlank(fileName)) { + // file_name/name 均为非空列,缺文件名视为转换失败直接跳过。 + log.warn("文件字段 [{}] 的第 {} 个文件缺少 filename,已跳过", fieldName, i); + continue; + } + OnlineFile onlineFile = new OnlineFile(); + onlineFile.setBaseUrl(fileItem.getString("baseUrl")); + onlineFile.setDownloadUri(fileItem.getString("downloadUri")); + onlineFile.setFileName(fileName); + onlineFile.setUploadPath(fileItem.getString("uploadPath")); + onlineFile.setName(fileItem.getString("name") == null ? fileName : fileItem.getString("name")); + onlineFile.setUrl(fileItem.getString("url")); + onlineFile.setCreateUserId(operatorUserId); + onlineFile.setUpdateUserId(operatorUserId); + fileList.add(onlineFile); + } + if (CollUtil.isEmpty(fileList) && fileArray.size() > 0) { + log.warn("文件字段 [{}] 的数据全部转换失败,保留原有附件", fieldName); + return null; + } + return fileList; + } + + private JSONArray toJsonArray(Object fileValue) { + if (fileValue == null) { + return null; + } + if (fileValue instanceof JSONArray) { + return (JSONArray) fileValue; + } + if (fileValue instanceof Collection) { + return new JSONArray(new LinkedList<>((Collection) fileValue)); + } + // 兼容单文件写法:{"filename": ...} 视为只含一个文件的数组。 + JSONObject singleFile = this.toJsonObject(fileValue); + if (singleFile != null) { + JSONArray singleArray = new JSONArray(); + singleArray.add(singleFile); + return singleArray; + } + if (fileValue instanceof String) { + String text = ((String) fileValue).trim(); + if (StrUtil.isBlank(text)) { + return null; + } + try { + if (text.startsWith("{")) { + JSONArray singleArray = new JSONArray(); + singleArray.add(JSON.parseObject(text)); + return singleArray; + } + return JSON.parseArray(text); + } catch (Exception e) { + return null; + } + } + return null; + } + + private JSONObject toJsonObject(Object fileItem) { + if (fileItem instanceof JSONObject) { + return (JSONObject) fileItem; + } + if (fileItem instanceof Map) { + return new JSONObject((Map) fileItem); + } + return null; + } + }