|
@@ -2,19 +2,40 @@ package com.persagy.dmp.file.service.impl;
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.io.FileUtil;
|
|
|
+import cn.hutool.core.util.NumberUtil;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
import cn.hutool.core.util.RandomUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.persagy.dmp.common.constant.ResponseCode;
|
|
|
+import com.persagy.dmp.common.context.AppContext;
|
|
|
+import com.persagy.dmp.common.exception.BusinessException;
|
|
|
+import com.persagy.dmp.common.lang.PsDate;
|
|
|
+import com.persagy.dmp.common.lang.PsDateTime;
|
|
|
+import com.persagy.dmp.file.constant.UploadCodeEnum;
|
|
|
+import com.persagy.dmp.file.domain.FileRequestData;
|
|
|
+import com.persagy.dmp.file.domain.UploadMes;
|
|
|
+import com.persagy.dmp.file.domain.UploadSubMes;
|
|
|
import com.persagy.dmp.file.model.FileInfo;
|
|
|
import com.persagy.dmp.file.model.FileInfoCreator;
|
|
|
+import com.persagy.dmp.file.model.FileMd5;
|
|
|
+import com.persagy.dmp.file.model.FileMd5Creator;
|
|
|
+import com.persagy.dmp.file.service.FileMd5Service;
|
|
|
import com.persagy.dmp.file.service.IFileService;
|
|
|
import com.persagy.dmp.file.dao.FileMapper;
|
|
|
import com.persagy.dmp.common.constant.ValidEnum;
|
|
|
+import com.persagy.dmp.storage.constant.FileCommonConst;
|
|
|
+import com.persagy.dmp.storage.service.FileStorageFactory;
|
|
|
+import com.persagy.dmp.storage.service.IFileStorageService;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
|
|
|
/**
|
|
|
* 文件服务实现类
|
|
@@ -23,11 +44,14 @@ import java.util.List;
|
|
|
*/
|
|
|
@Service
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
+@RequiredArgsConstructor
|
|
|
public class FileServiceImpl extends ServiceImpl<FileMapper, FileInfo> implements IFileService {
|
|
|
|
|
|
+ private final FileMd5Service fileMd5Service;
|
|
|
+
|
|
|
@Override
|
|
|
public FileInfo insertFile(FileInfo vo) {
|
|
|
- ensureFilePath(vo);
|
|
|
+ //ensureFilePath(vo);
|
|
|
save(vo);
|
|
|
return vo;
|
|
|
}
|
|
@@ -36,14 +60,14 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, FileInfo> implement
|
|
|
public FileInfo updateFile(FileInfo vo) {
|
|
|
FileInfo dbVO = load(vo.getId());
|
|
|
vo.setCreationTime(dbVO.getCreationTime());
|
|
|
- ensureFilePath(vo);
|
|
|
+ //ensureFilePath(vo);
|
|
|
updateById(vo);
|
|
|
return vo;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public List<FileInfo> batchInsert(List<FileInfo> voList) {
|
|
|
- voList.forEach(vo -> ensureFilePath(vo));
|
|
|
+ //voList.forEach(vo -> ensureFilePath(vo));
|
|
|
saveBatch(voList);
|
|
|
return voList;
|
|
|
}
|
|
@@ -71,41 +95,216 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, FileInfo> implement
|
|
|
return list(queryWrapper);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 确认文件名称
|
|
|
- * @param vo 文件管理对象
|
|
|
- * @return
|
|
|
+ /***
|
|
|
+ * Description: 初始化文件上传路径列表
|
|
|
+ * @param requestData : 请求参数
|
|
|
+ * @return : java.util.List<com.persagy.dmp.file.model.FileInfo>
|
|
|
+ * @author : lijie
|
|
|
+ * @date :2021/10/9 20:27
|
|
|
+ * Update By lijie 2021/10/9 20:27
|
|
|
*/
|
|
|
- private void ensureFilePath(FileInfo vo) {
|
|
|
- // 组装文件路径 - 日期以文件创建日期为准
|
|
|
- FileInfoCreator.buildFilePath(vo);
|
|
|
- // 是否存在同名
|
|
|
- LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
- queryWrapper.
|
|
|
- eq(FileInfo::getValid, ValidEnum.TRUE.getType()).
|
|
|
- eq(FileInfo::getFilePath, vo.getFilePath());
|
|
|
- if(StrUtil.isNotBlank(vo.getId())) {
|
|
|
- queryWrapper.ne(FileInfo::getId, vo.getId());
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public UploadMes initChunkUpload(FileRequestData requestData) {
|
|
|
+ IFileStorageService service = FileStorageFactory.getService();
|
|
|
+ // 1.根据文件md5值查询数据库
|
|
|
+ FileMd5 fileMd5 = fileMd5Service.queryFileMd5ByFileMd5(requestData.getFileMd5());
|
|
|
+ // 2.历史已上传且已完成上传
|
|
|
+ if (ObjectUtil.isNotNull(fileMd5)
|
|
|
+ && FileCommonConst.UPLOAD_SUCCESS.equals(fileMd5.getUploadStatus())){
|
|
|
+ // 秒传
|
|
|
+ return secondTransmission(requestData.getFileName(),requestData.getGroupCode(),
|
|
|
+ requestData.getBusinessId(),requestData.getExpireDate(),fileMd5.getFileMd5());
|
|
|
+ }
|
|
|
+ // 3.历史已上传且已上传分片
|
|
|
+ if (ObjectUtil.isNotNull(fileMd5)){
|
|
|
+ //获取到该文件已上传分片
|
|
|
+ Map<Integer,String> okChunkMap = service
|
|
|
+ .mapChunkObjectNames(service.getChuckBucketName(null), requestData.getFileMd5());
|
|
|
+ List<UploadSubMes> chunkUploadUrls = new ArrayList<>();
|
|
|
+ if (okChunkMap.size() > 0){
|
|
|
+ for (int i = 1; i <= requestData.getChunkCount(); i++) {
|
|
|
+ //判断当前分片是否已经上传过了
|
|
|
+ if(okChunkMap.containsKey(i)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ //生成分片上传url
|
|
|
+ UploadSubMes url = new UploadSubMes();
|
|
|
+ url.setPartNumber(i);
|
|
|
+ url.setUploadUrl(service.createUploadChunkUrl(requestData.getFileBucket(),
|
|
|
+ requestData.getFileMd5(),i));
|
|
|
+ chunkUploadUrls.add(url);
|
|
|
+ }
|
|
|
+ if (chunkUploadUrls.size() == 0){
|
|
|
+ // 分片已经全部上传,只需要合并文件操作
|
|
|
+ UploadMes uploadMes = new UploadMes();
|
|
|
+ uploadMes.setUploadCode(UploadCodeEnum.CODE_202.getCode());
|
|
|
+ return uploadMes;
|
|
|
+ }
|
|
|
+ UploadMes uploadMes = new UploadMes();
|
|
|
+ uploadMes.setUploadCode(UploadCodeEnum.CODE_203.getCode());
|
|
|
+ uploadMes.setContent(chunkUploadUrls);
|
|
|
+ return uploadMes;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 4.第一次上传或已存在但没有上传过分片的
|
|
|
+ return firstInitChunkUploadInternal(requestData);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /***
|
|
|
+ * Description: 合并断点续传的文件
|
|
|
+ * @param requestData : 请求参数
|
|
|
+ * @return : com.persagy.dmp.file.model.FileInfo
|
|
|
+ * @author : lijie
|
|
|
+ * @date :2021/10/20 21:57
|
|
|
+ * Update By lijie 2021/10/20 21:57
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public FileInfo composeFile(FileRequestData requestData) {
|
|
|
+ IFileStorageService service = FileStorageFactory.getService();
|
|
|
+ // 1.根据md5获取所有分片文件名称(minio的文件名称 = 文件path)
|
|
|
+ List<String> chunks = service
|
|
|
+ .listObjectNames(service.getChuckBucketName(null),requestData.getFileMd5());
|
|
|
+ if (CollUtil.isEmpty(chunks)){
|
|
|
+ throw new BusinessException(ResponseCode.A0400.getCode(), "分片文件数量为空");
|
|
|
+ }
|
|
|
+ // 2.获取数据库里记录的文件信息,修改数据并返回文件信息
|
|
|
+ FileMd5 fileMd5 = fileMd5Service.queryFileMd5ByFileMd5(requestData.getFileMd5());
|
|
|
+ if (null==fileMd5){
|
|
|
+ throw new BusinessException(ResponseCode.A0400.getCode(), "文件信息为空");
|
|
|
+ }
|
|
|
+ // 3.保存文件信息
|
|
|
+ FileInfo fileInfo = FileInfoCreator.of(requestData.getGroupCode(),requestData.getFileName(),
|
|
|
+ requestData.getBusinessId(),fileMd5.getFileMd5(),requestData.getExpireDate());
|
|
|
+ fileInfo.setCreator(AppContext.getContext().getAccountId());
|
|
|
+ // 4.计算文件上传路径
|
|
|
+ fileMd5Service.ensureFilePath(fileMd5,fileInfo.getFileName(),requestData.getGroupCode());
|
|
|
+ // 5.合并文件
|
|
|
+ if(service.composeObject(requestData.getFileBucket(),chunks,fileMd5.getFilePath())){
|
|
|
+ fileMd5.setUploadStatus(FileCommonConst.UPLOAD_SUCCESS);
|
|
|
+ fileMd5.setFileBucket(requestData.getFileBucket());
|
|
|
+ fileMd5.setFileSize(service.getObjectSize(fileMd5.getFileBucket(), fileMd5.getFilePath()));
|
|
|
+ fileMd5Service.updateById(fileMd5);
|
|
|
+ this.save(fileInfo);
|
|
|
+ return fileInfo;
|
|
|
}
|
|
|
- List<FileInfo> dbVos = list(queryWrapper);
|
|
|
- if(CollUtil.isEmpty(dbVos)) {
|
|
|
- return;
|
|
|
+ throw new BusinessException(ResponseCode.B0001.getCode(), "合并文件失败");
|
|
|
+ }
|
|
|
+ /***
|
|
|
+ * Description:
|
|
|
+ * @param requestData :
|
|
|
+ * @return : com.persagy.dmp.file.domain.UploadMes
|
|
|
+ * @author : lijie
|
|
|
+ * @date :2021/10/22 19:29
|
|
|
+ * Update By lijie 2021/10/22 19:29
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public UploadMes initSingleUpload(FileRequestData requestData) {
|
|
|
+ IFileStorageService service = FileStorageFactory.getService();
|
|
|
+ // 1.根据文件md5值查询数据库
|
|
|
+ FileMd5 fileMd5 = fileMd5Service.queryFileMd5ByFileMd5(requestData.getFileMd5());
|
|
|
+ // 2.历史已上传但未上传完成
|
|
|
+ if (ObjectUtil.isNotNull(fileMd5)
|
|
|
+ && FileCommonConst.UPLOAD_PART.equals(fileMd5.getUploadStatus())) {
|
|
|
+ // 组装上传信息
|
|
|
+ throw new BusinessException(ResponseCode.B0300.getCode(),ResponseCode.B0300.getDesc());
|
|
|
+ }
|
|
|
+ // 3.历史已上传且已完成上传
|
|
|
+ if (ObjectUtil.isNotNull(fileMd5)
|
|
|
+ && FileCommonConst.UPLOAD_SUCCESS.equals(fileMd5.getUploadStatus())){
|
|
|
+ // 秒传
|
|
|
+ return secondTransmission(requestData.getFileName(),requestData.getGroupCode(),
|
|
|
+ requestData.getBusinessId(),requestData.getExpireDate(),fileMd5.getFileMd5());
|
|
|
}
|
|
|
- // 存在同名 - 重新命名 +随机数
|
|
|
- vo.setFileName(resetFileName(vo.getFileName()));
|
|
|
- ensureFilePath(vo);
|
|
|
+ FileInfo fileInfo = FileInfoCreator
|
|
|
+ .of(requestData.getGroupCode(), requestData.getFileName(), requestData.getBusinessId(),
|
|
|
+ requestData.getFileMd5(),requestData.getExpireDate());
|
|
|
+ fileInfo.setCreator(AppContext.getContext().getAccountId());
|
|
|
+ fileMd5 = FileMd5Creator.of(requestData.getFileBucket(), requestData.getFileMd5(), FileCommonConst.UPLOAD_SUCCESS);
|
|
|
+ fileMd5.setFileSize(requestData.getFileSize());
|
|
|
+ fileMd5.setCreationTime(new PsDateTime());
|
|
|
+ fileMd5Service.ensureFilePath(fileMd5,requestData.getFileName(),requestData.getGroupCode());
|
|
|
+ String uploadUrl = service.createUploadUrl(fileMd5.getFileBucket(), fileMd5.getFilePath());
|
|
|
+ this.save(fileInfo);
|
|
|
+ fileMd5Service.save(fileMd5);
|
|
|
+ UploadMes uploadMes = new UploadMes();
|
|
|
+ uploadMes.setUploadCode(UploadCodeEnum.CODE_201.getCode());
|
|
|
+ UploadSubMes uploadSubMes = new UploadSubMes();
|
|
|
+ uploadSubMes.setPartNumber(0);
|
|
|
+ uploadSubMes.setUploadUrl(uploadUrl);
|
|
|
+ uploadMes.setContent(CollUtil.newArrayList(uploadSubMes));
|
|
|
+ return uploadMes;
|
|
|
+ }
|
|
|
+ /***
|
|
|
+ * Description: 根据Md5查询文件信息
|
|
|
+ * @param fileMd5 : 文件md5值
|
|
|
+ * @return : java.util.List<com.persagy.dmp.file.model.FileInfo>
|
|
|
+ * @author : lijie
|
|
|
+ * @date :2021/10/22 22:36
|
|
|
+ * Update By lijie 2021/10/22 22:36
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<FileInfo> queryByFileMd5(String fileMd5) {
|
|
|
+ LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(FileInfo::getFileMd5,fileMd5);
|
|
|
+ queryWrapper.eq(FileInfo::getValid,true);
|
|
|
+ return this.list(queryWrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /***
|
|
|
+ * Description: 秒传逻辑
|
|
|
+ * @param fileName : 文件名称
|
|
|
+ * @param groupCode : 集团编码
|
|
|
+ * @param businessId : 业务id
|
|
|
+ * @param expireDate : 过期时间
|
|
|
+ * @return : com.persagy.dmp.file.domain.FileView
|
|
|
+ * @author : lijie
|
|
|
+ * @date :2021/10/22 10:03
|
|
|
+ * Update By lijie 2021/10/22 10:03
|
|
|
+ */
|
|
|
+ private UploadMes secondTransmission(String fileName, String groupCode,
|
|
|
+ String businessId, PsDate expireDate,String fileMd5) {
|
|
|
+ // 1.生成文件信息并返回
|
|
|
+ FileInfo fileInfo = FileInfoCreator.of(groupCode,fileName,businessId,fileMd5,expireDate);
|
|
|
+ fileInfo.setCreator(AppContext.getContext().getAccountId());
|
|
|
+ // 2.保存文件信息
|
|
|
+ this.save(fileInfo);
|
|
|
+ // 3.组装上传信息
|
|
|
+ UploadMes uploadMes = new UploadMes();
|
|
|
+ uploadMes.setFileId(fileInfo.getId());
|
|
|
+ uploadMes.setUploadCode(UploadCodeEnum.CODE_200.getCode());
|
|
|
+ return uploadMes;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 重命名
|
|
|
- * @param oldFileName 原文件名
|
|
|
- * @return 原文件名前缀+"-随机数"+后缀
|
|
|
+ /***
|
|
|
+ * Description: 初次上传和已有文件信息但未上传任何分片的情况下则直接生成所有上传url
|
|
|
+ * @param requestData :
|
|
|
+ * @return : java.util.List<com.persagy.dmp.file.model.FileInfo>
|
|
|
+ * @author : lijie
|
|
|
+ * @date :2021/10/9 20:36
|
|
|
+ * Update By lijie 2021/10/9 20:36
|
|
|
*/
|
|
|
- private String resetFileName(String oldFileName) {
|
|
|
- StringBuilder fileName = new StringBuilder();
|
|
|
- fileName.append(FileUtil.getPrefix(oldFileName)).append("-");
|
|
|
- fileName.append(RandomUtil.randomInt(100000)).append(".");
|
|
|
- fileName.append(FileUtil.getSuffix(oldFileName));
|
|
|
- return fileName.toString();
|
|
|
+ private UploadMes firstInitChunkUploadInternal(FileRequestData requestData) {
|
|
|
+ IFileStorageService service = FileStorageFactory.getService();
|
|
|
+ List<String> uploadUrls = service
|
|
|
+ .createUploadChunkUrlList(service.getChuckBucketName(null),
|
|
|
+ requestData.getFileMd5(), requestData.getChunkCount());
|
|
|
+ List<UploadSubMes> chunkUploadUrls = new ArrayList<>();
|
|
|
+ for (int i = 1; i <= uploadUrls.size(); i++) {
|
|
|
+ UploadSubMes fileInfo = new UploadSubMes();
|
|
|
+ fileInfo.setPartNumber(i);
|
|
|
+ fileInfo.setUploadUrl(service.createUploadChunkUrl(requestData.getFileBucket(),
|
|
|
+ requestData.getFileMd5(),i));
|
|
|
+ chunkUploadUrls.add(fileInfo);
|
|
|
+ }
|
|
|
+ //向数据库中记录该文件的Md5上传信息
|
|
|
+ FileMd5 fileMd5 = FileMd5Creator.of(requestData.getFileBucket(),requestData.getFileMd5(),FileCommonConst.UPLOAD_PART);
|
|
|
+ fileMd5Service.save(fileMd5);
|
|
|
+ UploadMes uploadMes = new UploadMes();
|
|
|
+ uploadMes.setUploadCode(UploadCodeEnum.CODE_203.getCode());
|
|
|
+ uploadMes.setContent(chunkUploadUrls);
|
|
|
+ return uploadMes;
|
|
|
}
|
|
|
+
|
|
|
}
|