Browse Source

feat(online-file): 新增按表名全量替换附件字段的方法

- 在 OnlineFileService 接口新增 replaceFileListByTableName 方法定义
- 实现按物理表名查询 OnlineTable 并逐字段替换附件数据
- 支持 JSONArray、Collection、单文件对象、JSON 字符串等多种输入格式
- 解析失败时保留旧附件,空数组时清空该字段附件
- 兼容缺少 name 字段时自动使用 filename 作为回退值
- 添加 @Slf4j 日志和 @Transactional 事务注解
- pom.xml 新增 common-core 依赖并将版本升级至 1.0.5.1
stable/2026-11-online-1.0.5
chenchuchuan 20 hours ago
parent
commit
f97d006405
  1. 7
      common/common-online/pom.xml
  2. 13
      common/common-online/src/main/java/apelet/common/online/service/OnlineFileService.java
  3. 128
      common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFileServiceImpl.java

7
common/common-online/pom.xml

@ -10,13 +10,18 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>common-online</artifactId> <artifactId>common-online</artifactId>
<version>1.0.5</version> <version>1.0.5.1</version>
<name>common-online</name> <name>common-online</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>apelet</groupId> <groupId>apelet</groupId>
<artifactId>common-core</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>apelet</groupId>
<artifactId>common-dbutil</artifactId> <artifactId>common-dbutil</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>

13
common/common-online/src/main/java/apelet/common/online/service/OnlineFileService.java

@ -1,6 +1,7 @@
package apelet.common.online.service; package apelet.common.online.service;
import apelet.common.online.model.OnlineFile; import apelet.common.online.model.OnlineFile;
import com.alibaba.fastjson.JSONObject;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -51,4 +52,16 @@ public interface OnlineFileService {
*/ */
Map<Long, List<OnlineFile>> getOnlineFileMapByBusinessIds( Map<Long, List<OnlineFile>> getOnlineFileMapByBusinessIds(
Long onlineTableId, String fieldName, List<Long> businessIdList); Long onlineTableId, String fieldName, List<Long> businessIdList);
/**
* 按表名和业务Id全量替换附件字段:key为字段名,value为该字段的文件JSON数组。
* <p>只处理入参中出现且能解析出文件数组的字段,其它字段的附件数据保持不动;
* value 整体解析失败时该字段按"保留旧附件"处理,空数组则清空该字段附件。</p>
*
* @param tableName 物理表名称(zz_online_table.table_name),分录字段传分录表自己的表名。
* @param businessId 业务Id(所在表记录主键值)。
* @param fileData key为字段名,value为文件JSON数组。
*/
void replaceFileListByTableName(String tableName, Long businessId, JSONObject fileData);
} }

128
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.annotation.MyDataSourceResolver;
import apelet.common.core.constant.ApplicationConstant; import apelet.common.core.constant.ApplicationConstant;
import apelet.common.core.object.TokenData;
import apelet.common.core.util.DefaultDataSourceResolver; import apelet.common.core.util.DefaultDataSourceResolver;
import apelet.common.online.dao.OnlineFileMapper; import apelet.common.online.dao.OnlineFileMapper;
import apelet.common.online.model.OnlineFile; import apelet.common.online.model.OnlineFile;
import apelet.common.online.model.OnlineTable;
import apelet.common.online.service.OnlineFileService; import apelet.common.online.service.OnlineFileService;
import apelet.common.online.service.OnlineTableService;
import apelet.common.sequence.wrapper.IdGeneratorWrapper; import apelet.common.sequence.wrapper.IdGeneratorWrapper;
import cn.hutool.core.collection.CollUtil; 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 com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Date; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -25,6 +32,7 @@ import java.util.stream.Collectors;
* @author guifc * @author guifc
* @date 2023-08-04 * @date 2023-08-04
*/ */
@Slf4j
@MyDataSourceResolver( @MyDataSourceResolver(
resolver = DefaultDataSourceResolver.class, resolver = DefaultDataSourceResolver.class,
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE) intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
@ -34,6 +42,8 @@ public class OnlineFileServiceImpl implements OnlineFileService {
@Autowired @Autowired
private OnlineFileMapper onlineFileMapper; private OnlineFileMapper onlineFileMapper;
@Autowired @Autowired
private OnlineTableService onlineTableService;
@Autowired
private IdGeneratorWrapper idGenerator; private IdGeneratorWrapper idGenerator;
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -90,4 +100,114 @@ public class OnlineFileServiceImpl implements OnlineFileService {
.in("business_id", businessIdList)); .in("business_id", businessIdList));
return fileList.stream().collect(Collectors.groupingBy(OnlineFile::getBusinessId)); 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<OnlineTable>().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<OnlineFile> fileList = this.parseOnlineFileList(fileData.get(fieldName), fieldName, operatorUserId);
// 解析失败返回null,按保留旧附件处理;空数组则清空该字段附件。
if (fileList == null) {
continue;
}
this.replaceFileList(table.getTableId(), fieldName, businessId, fileList);
}
}
/**
* 把文件字段的JSON数组解析为 OnlineFile 列表。
* <p>值为空、不是数组或数组内没有任何可用文件时返回null,交由调用方按"保留旧附件"处理。</p>
*/
private List<OnlineFile> parseOnlineFileList(Object fileValue, String fieldName, Long operatorUserId) {
JSONArray fileArray = this.toJsonArray(fileValue);
if (fileArray == null) {
log.warn("文件字段 [{}] 的数据无法解析为JSON数组,保留原有附件", fieldName);
return null;
}
List<OnlineFile> 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<String, Object>) fileItem);
}
return null;
}
} }

Loading…
Cancel
Save