fix: 修复tempFilePaths和records对应关系的潜在bug

问题:
- 原代码中保存临时文件和创建记录使用两个独立的循环
- 无法保证两个列表的索引严格一一对应
- 如果中间出现异常或跳过,会导致对应关系错乱

修复:
- 将两个循环合并为一个,在同一个循环中处理
- 使用相同的索引i创建tempFilePaths[i]和records[i]
- 添加数量一致性验证
- 临时文件名中加入索引i,避免文件名冲突
- 日志中记录索引i便于调试

影响:
- 确保临时文件和数据库记录严格一一对应
- 避免异步处理时出现文件与记录不匹配的问题
This commit is contained in:
wkc
2026-03-05 13:47:39 +08:00
parent d8d60f9103
commit 756129b913

View File

@@ -166,8 +166,11 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
log.info("【文件上传】项目信息验证通过: projectId={}, lsfxProjectId={}", projectId, lsfxProjectId);
// Critical Fix #2: 保存MultipartFile到临时存储,避免异步处理时文件已被清理
// Critical Fix #2 & #4: 保存临时文件和创建记录在同一个循环中,确保一一对应
List<String> tempFilePaths = new ArrayList<>();
List<CcdiFileUploadRecord> records = new ArrayList<>();
Date now = new Date();
try {
// 确保临时目录存在
Path tempDir = Paths.get(getTempFileDir());
@@ -175,39 +178,41 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
Files.createDirectories(tempDir);
}
// 保存所有文件到临时目录
for (MultipartFile file : files) {
// 同一个循环中保存临时文件和创建记录,确保索引一一对应
for (int i = 0; i < files.length; i++) {
MultipartFile file = files[i];
// 1. 保存临时文件
String originalFilename = file.getOriginalFilename();
String tempFileName = batchId + "_" + System.currentTimeMillis() + "_" + originalFilename;
String tempFileName = batchId + "_" + i + "_" + System.currentTimeMillis() + "_" + originalFilename;
Path tempFilePath = tempDir.resolve(tempFileName);
// 将MultipartFile内容复制到临时文件
Files.copy(file.getInputStream(), tempFilePath, StandardCopyOption.REPLACE_EXISTING);
tempFilePaths.add(tempFilePath.toString());
log.debug("【文件上传】保存临时文件: originalName={}, tempPath={}",
originalFilename, tempFilePath);
log.debug("【文件上传】保存临时文件[{}]: originalName={}, tempPath={}",
i, originalFilename, tempFilePath);
// 2. 创建记录使用相同的索引i
CcdiFileUploadRecord record = new CcdiFileUploadRecord();
record.setProjectId(projectId);
record.setLsfxProjectId(lsfxProjectId);
record.setFileName(originalFilename);
record.setFileSize(file.getSize());
record.setFileStatus("uploading");
record.setUploadTime(now);
record.setUploadUser(username);
records.add(record);
}
} catch (IOException e) {
log.error("【文件上传】保存临时文件失败", e);
throw new RuntimeException("保存临时文件失败: " + e.getMessage(), e);
}
// 3. 批量插入文件记录(status=uploading)
List<CcdiFileUploadRecord> records = new ArrayList<>();
Date now = new Date();
for (int i = 0; i < files.length; i++) {
MultipartFile file = files[i];
CcdiFileUploadRecord record = new CcdiFileUploadRecord();
record.setProjectId(projectId);
record.setLsfxProjectId(lsfxProjectId);
record.setFileName(file.getOriginalFilename());
record.setFileSize(file.getSize());
record.setFileStatus("uploading");
record.setUploadTime(now);
record.setUploadUser(username);
records.add(record);
// 验证数量一致性
if (tempFilePaths.size() != records.size()) {
throw new RuntimeException(String.format(
"临时文件数量(%d)与记录数量(%d)不一致", tempFilePaths.size(), records.size()));
}
recordMapper.insertBatch(records);