修改:多文件,分片上传接口修改。

This commit is contained in:
yangyang01000846
2025-11-24 16:17:32 +08:00
parent 87ef062f81
commit 64fd64ad90
3 changed files with 85 additions and 52 deletions

View File

@@ -96,10 +96,6 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
@Value("${fileSystem.chunkBucket:spdm}")
private String chunkBucket;
// 路径待确定 待配置及初始化
@Value("${fileSystem.chunkBasePath:/chunkBase}")
private String chunkBasePath;
@Autowired
private IFileMetadataInfoService fileMetadataInfoService;
@@ -223,58 +219,52 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
public SdmResponse<ChunkUploadMinioFileResp> chunkUploadToMinio(ChunkUploadMinioFileReq req) {
ChunkUploadMinioFileResp resp = new ChunkUploadMinioFileResp();
// 基础路径配置
Long tenantId = ThreadLocalContext.getTenantId();
// Long tenantId = 123456l;
// Long userId = 9999l;
Long userId= ThreadLocalContext.getUserId();
// -2. 参数校验
try {
validateReq(req,tenantId,userId);
validateReq(req);
} catch (Exception e) {
CoreLogger.error("validateReq error{}", e.getMessage());
return buildFailedResponse(resp,e.getMessage(),"",chunkBucket);
return buildFailedResponse(resp,e.getMessage(),req);
}
// -1.确定文件夹
String timestamp = String.valueOf(System.currentTimeMillis());
// 合并目录
String filePath = org.apache.commons.lang3.StringUtils.isNotBlank(req.getFileDirPath())?
req.getFileDirPath():chunkBasePath + "/" + tenantId + "/" + userId +"/" + timestamp + "/";
String filePath = getMinioFolderPath(req.getObjectKey());
// 0. 一个文件直接传
if(Objects.equals(req.getChunkTotal(),NumberConstants.ONE)&&
Objects.equals(req.getChunk(),NumberConstants.ONE)){
String finalFileName = filePath + req.getSourceFileName();
Boolean b = minioService.chunkUpload(chunkBucket, req.getFile(), finalFileName);
if(!b){
return buildFailedResponse(resp,"单一文件上传失败",filePath,chunkBucket);
return buildFailedResponse(resp,"单一文件上传失败",req);
}
return buildSuccessResponse(resp,finalFileName,filePath,chunkBucket);
return buildSuccessResponse(resp,req,"");
}
String tempDirPath = filePath +"temp/";
// 碎片目录
String tempDirPath = org.apache.commons.lang3.StringUtils.isBlank(req.getFileTempPath())?
filePath +"temp/"+timestamp+"/":req.getFileTempPath();
// 1. 保存当前分片到临时目录 1 2 3 4 ....temp
String chunkFileName =tempDirPath+req.getChunk()+ PermConstants.CHUNK_TEMPFILE_SUFFIX;
// 片文件上传到minio
Boolean b = minioService.chunkUpload(chunkBucket, req.getFile(), chunkFileName);
if(!b){
return buildFailedResponse(resp,"chunkUpload第"+req.getChunk()+"次失败",filePath,chunkBucket);
deleteTempFileAfterFailed(tempDirPath,chunkBucket);
return buildFailedResponse(resp,"chunkUpload第"+req.getChunk()+"次失败",req);
}
// 2. 判断分片是否已全部上传完毕
if (req.getChunk() < req.getChunkTotal()) {
return buildSuccessResponse(resp,"",filePath,chunkBucket);
return buildSuccessResponse(resp,req,tempDirPath);
}
// 3. 全部分片已经上传 => 自动合并
String finalFileName = filePath + req.getSourceFileName();
Boolean merge = minioService.merge(chunkBucket, tempDirPath, chunkBucket, finalFileName);
if(!merge){
return buildFailedResponse(resp,req.getSourceFileName()+"合并分片失败",filePath,chunkBucket);
deleteTempFileAfterFailed(tempDirPath,chunkBucket);
return buildFailedResponse(resp,req.getSourceFileName()+"合并分片失败",req);
}
// 4. 合并完成后删除临时目录
String finalTempDirPath=tempDirPath;
String finalChunkBucket=chunkBucket;
CompletableFuture.runAsync(() -> {
minioService.deleteDirectoryRecursively2(finalTempDirPath, finalChunkBucket);
}, nonSensitiveTaskPool);
return buildSuccessResponse(resp,finalFileName,filePath,chunkBucket);
deleteTempFileAfterFailed(tempDirPath,chunkBucket);
return buildSuccessResponse(resp,req,tempDirPath);
}
@@ -2148,10 +2138,8 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
/**
* 参数校验
*/
private void validateReq(ChunkUploadMinioFileReq req, Long tenantId, Long userId) {
private void validateReq(ChunkUploadMinioFileReq req) {
// 基础参数校验
Assert.notNull(tenantId, "租户ID不能为空");
Assert.notNull(userId, "用户ID不能为空");
Assert.hasText(req.getSourceFileName(), "原始文件名称不能为空");
Assert.notNull(req.getChunk(), "分片编号不能为空");
Assert.notNull(req.getChunkTotal(), "分片总数不能为空");
@@ -2161,28 +2149,60 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
Assert.isTrue(req.getChunk() >= 1 && req.getChunk() <= req.getChunkTotal(),
"分片编号非法:当前" + req.getChunk() + ",总分片" + req.getChunkTotal());
Assert.isTrue(req.getChunkTotal() >= 1, "分片总数必须大于等于1");
Assert.hasText(req.getObjectKey(), "文件存储位置不能为空");
Assert.hasText(req.getUploadTaskId(), "文件上传任务Id不能为空");
Assert.notNull(req.getBusinessId(), "文件绑定业务Id不能为空");
if(req.getChunk() > NumberConstants.ONE) {
Assert.hasText(req.getFileDirPath(), "分片父级目录不允许为空");
Assert.hasText(req.getFileTempPath(), "分片临时目录不允许为空");
}
}
// 包含业务数据的响应体
private SdmResponse<ChunkUploadMinioFileResp> buildSuccessResponse(ChunkUploadMinioFileResp resp, String finalFileName, String fileDirPath,String chunkBucket) {
resp.setBucketName(chunkBucket);
resp.setFilePath(finalFileName);
resp.setFileDirPath(fileDirPath);
// 成功时,错误信息通常为空
resp.setErrMsg("");
return SdmResponse.success(resp);
}
// 包含业务数据的响应体
private SdmResponse<ChunkUploadMinioFileResp> buildSuccessResponse(ChunkUploadMinioFileResp resp, ChunkUploadMinioFileReq req,String fileTempPath) {
resp.setResult(true);
resp.setBusinessId(req.getBusinessId());
resp.setUploadTaskId(req.getUploadTaskId());
resp.setFileTempPath(fileTempPath);
// 成功时,错误信息通常为空
resp.setErrMsg("");
return SdmResponse.success(resp);
}
// 构建一个失败的响应对象
private SdmResponse<ChunkUploadMinioFileResp> buildFailedResponse(ChunkUploadMinioFileResp resp, String errMsg, String fileDirPath,String chunkBucket) {
resp.setBucketName(chunkBucket);
resp.setFileDirPath(fileDirPath);
// 构建一个失败的响应对象
private SdmResponse<ChunkUploadMinioFileResp> buildFailedResponse(ChunkUploadMinioFileResp resp, String errMsg,ChunkUploadMinioFileReq req) {
resp.setResult(false);
resp.setBusinessId(req.getBusinessId());
resp.setUploadTaskId(req.getUploadTaskId());
// 如果 errMsg 为 null设置为空字符串 ""
resp.setErrMsg(errMsg != null ? errMsg : "");
return SdmResponse.failed(resp);
}
/**
* 从文件路径字符串中获取文件夹路径(仅适用于 '/' 作为分隔符的情况)
* @param filePath 完整文件路径knowledge/20251111-yy/仿真地图 (46)_V1.xls
* @return 文件夹路径knowledge/20251111-yy/),若输入为空或无分隔符则返回原路径
*/
private static String getMinioFolderPath(String filePath) {
// 1. 校验输入合法性
if (filePath == null || filePath.trim().isEmpty()) {
return filePath;
}
// 2. 查找最后一个 '/' 分隔符的位置
int lastSeparatorIndex = filePath.lastIndexOf("/");
// 3. 若未找到分隔符(说明是单纯文件名,无路径),返回原字符串
if (lastSeparatorIndex == -1) {
return filePath;
}
// 4. 截取从开头到最后一个分隔符(包含分隔符)的子字符串
return filePath.substring(0, lastSeparatorIndex + 1);
}
// 分片上传,异常的时候删除临时目录,假如后面断点续传,某些场景的删除要最后确定失败再删除
private void deleteTempFileAfterFailed(String tempFilePath,String finalChunkBucket) {
CompletableFuture.runAsync(() -> {
minioService.deleteDirectoryRecursively2(tempFilePath, finalChunkBucket);
}, nonSensitiveTaskPool);
}
}