Browse Source

完善文件服务的上传逻辑:
1.提供断点续传,秒传功能
2.调整FileStorageHelper,使其适应新的上传逻辑

lijie 3 years ago
parent
commit
697c020201
33 changed files with 1722 additions and 884 deletions
  1. 3 3
      dmp-business/dmp-rwd/pom.xml
  2. 26 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/constant/UploadCodeEnum.java
  3. 101 7
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileController.java
  4. 96 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileMd5Controller.java
  5. 0 62
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileUploadController.java
  6. 16 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/dao/FileMd5Mapper.java
  7. 0 4
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/AccountDTO.java
  8. 14 1
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/FileRequestData.java
  9. 19 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/UploadMes.java
  10. 15 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/UploadSubMes.java
  11. 66 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/FileMd5Service.java
  12. 0 34
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/FileUploadService.java
  13. 39 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/IFileService.java
  14. 138 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileMd5ServiceImpl.java
  15. 232 33
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileServiceImpl.java
  16. 0 175
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileUploadServiceImpl.java
  17. 15 3
      dmp-cloud/dmp-file/src/main/resources/db/init/schema.sql
  18. 11 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileClientFacade.java
  19. 14 5
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileManageClient.java
  20. 57 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileMd5Client.java
  21. 65 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileMd5ClientFacade.java
  22. 5 6
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileInfo.java
  23. 19 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileInfoCreator.java
  24. 65 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileMd5.java
  25. 44 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileMd5Creator.java
  26. 0 9
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/config/MinioConfig.java
  27. 5 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/constant/FileCommonConst.java
  28. 166 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/IFileStorageService.java
  29. 0 171
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/MinioCommonService.java
  30. 78 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/impl/HdfsStorageServiceImpl.java
  31. 0 357
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/impl/MinioCommonServiceImpl.java
  32. 364 6
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/impl/MinioStorageServiceImpl.java
  33. 49 8
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/utils/FileStorageHelper.java

+ 3 - 3
dmp-business/dmp-rwd/pom.xml

@@ -12,9 +12,9 @@
     <packaging>jar</packaging>
     <repositories>
         <repository>
-            <id>osgeo</id>
-            <name>Open Source Geospatial Foundation Repository</name>
-            <url>https://repo.osgeo.org/repository/release/</url>
+            <id>persagy</id>
+            <name>persagy Repository</name>
+            <url>http://47.93.132.139:8081/nexus/content/repositories/persagy/</url>
         </repository>
     </repositories>
 

+ 26 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/constant/UploadCodeEnum.java

@@ -0,0 +1,26 @@
+package com.persagy.dmp.file.constant;
+
+import lombok.Getter;
+
+/***
+ * Description: 上传标识
+ * @author : lijie
+ * @date :2021/10/22 14:37
+ * Update By lijie 2021/10/22 14:37
+ */
+@Getter
+public enum UploadCodeEnum {
+    /**文件上传成功code,200-秒传,201-单个文件上传,202-断点续传且文件分片均已上传,203-断点续传*/
+    CODE_200(200),
+    CODE_201(201),
+    CODE_202(202),
+    CODE_203(203);
+
+
+    private Integer code;
+
+    UploadCodeEnum(Integer code){
+        this.code=code;
+    }
+
+}

+ 101 - 7
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileController.java

@@ -3,17 +3,17 @@ package com.persagy.dmp.file.controller;
 import cn.hutool.core.util.StrUtil;
 import com.persagy.dmp.common.constant.ResponseCode;
 import com.persagy.dmp.common.constant.ValidEnum;
+import com.persagy.dmp.common.context.AppContext;
 import com.persagy.dmp.common.exception.BusinessException;
 import com.persagy.dmp.common.lang.PsDateTime;
 import com.persagy.dmp.common.model.response.CommonResult;
 import com.persagy.dmp.common.utils.ResultHelper;
+import com.persagy.dmp.file.domain.FileRequestData;
+import com.persagy.dmp.file.domain.UploadMes;
 import com.persagy.dmp.file.model.FileInfo;
 import com.persagy.dmp.file.service.IFileService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 
@@ -24,10 +24,10 @@ import java.util.List;
  */
 @RestController
 @RequestMapping("/file")
+@RequiredArgsConstructor
 public class FileController {
 
-    @Autowired
-    IFileService fileService;
+    private final IFileService fileService;
 
     @PostMapping("/insert")
     public CommonResult<FileInfo> insert(@RequestBody FileInfo fileInfo) {
@@ -88,4 +88,98 @@ public class FileController {
         List<FileInfo> voList = fileService.queryByBusinessId(businessId);
         return ResultHelper.multi(voList);
     }
+
+    @PostMapping("/queryByFileMd5")
+    public CommonResult<List<FileInfo>> queryByFileMd5(@RequestBody String fileMd5) {
+        if(StrUtil.isBlank(fileMd5)) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        List<FileInfo> voList = fileService.queryByFileMd5(fileMd5);
+        return ResultHelper.multi(voList);
+    }
+
+    /***
+     * Description: 初始化断点上传文件
+     * @param requestData : 请求参数
+     * @return : com.persagy.dmp.common.model.response.CommonResult<com.persagy.dmp.file.model.FileInfo>
+     * @author : lijie
+     * @date :2021/10/9 20:12
+     * Update By lijie 2021/10/9 20:12
+     */
+    @PostMapping("/initChunkUpload")
+    @CrossOrigin(origins = "*",allowCredentials = "true",methods = {RequestMethod.POST,RequestMethod.GET},maxAge = 3600)
+    public CommonResult<UploadMes> initChunkUpload(@RequestBody FileRequestData requestData) {
+        // 1.兼容一下groupCode
+        fillGroupCode(requestData);
+        // 2.判断必填项
+        if(StrUtil.isBlank(requestData.getFileName())
+                || StrUtil.isBlank(requestData.getFileMd5())
+                || StrUtil.isBlank(requestData.getGroupCode())) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        return ResultHelper.single(fileService.initChunkUpload(requestData));
+    }
+
+    /***
+     * Description: 初始化大文件上传
+     * @param requestData : 请求参数
+     * @return : com.persagy.dmp.common.model.response.CommonResult<com.persagy.dmp.file.model.FileInfo>
+     * @author : lijie
+     * @date :2021/10/9 20:12
+     * Update By lijie 2021/10/9 20:12
+     */
+    @PostMapping("/composeFile")
+    @CrossOrigin(origins = "*",allowCredentials = "true",methods = {RequestMethod.POST,RequestMethod.GET},maxAge = 3600)
+    public CommonResult<FileInfo> composeFile(@RequestBody FileRequestData requestData) {
+        //基础参数校验
+        // 1.兼容一下groupCode
+        fillGroupCode(requestData);
+        // 2.判断必填项
+        if(StrUtil.isBlank(requestData.getFileName())
+                || StrUtil.isBlank(requestData.getFileMd5())
+                || StrUtil.isBlank(requestData.getGroupCode())
+                || StrUtil.isBlank(requestData.getFileBucket())) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        return ResultHelper.single(fileService.composeFile(requestData));
+    }
+    /***
+     * Description: 初始化单个文件上传
+     * @param requestData : 请求参数
+     * @return : com.persagy.dmp.common.model.response.CommonResult<com.persagy.dmp.file.model.FileInfo>
+     * @author : lijie
+     * @date :2021/10/9 20:12
+     * Update By lijie 2021/10/9 20:12
+     */
+    @PostMapping("/initSingleUpload")
+    @CrossOrigin(origins = "*",allowCredentials = "true",methods = {RequestMethod.POST,RequestMethod.GET},maxAge = 3600)
+    public CommonResult<UploadMes> initSingleUpload(@RequestBody FileRequestData requestData) {
+        //基础参数校验
+        // 1.兼容一下groupCode
+        fillGroupCode(requestData);
+        // 2.判断必填项
+        if(StrUtil.isBlank(requestData.getFileName())
+                || StrUtil.isBlank(requestData.getFileMd5())
+                || StrUtil.isBlank(requestData.getGroupCode())
+                || StrUtil.isBlank(requestData.getFileBucket())) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        return ResultHelper.single(fileService.initSingleUpload(requestData));
+    }
+    /***
+     * Description: 填充一下集团编码
+     * @param requestData : 请求参数
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/21 20:14
+     * Update By lijie 2021/10/21 20:14
+     */
+    private void fillGroupCode(FileRequestData requestData) {
+        if (StrUtil.isNotBlank(requestData.getGroupCode())
+                || StrUtil.isBlank(AppContext.getContext().getGroupCode())){
+            return;
+        }
+        requestData.setGroupCode(AppContext.getContext().getGroupCode());
+    }
+
 }

+ 96 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileMd5Controller.java

@@ -0,0 +1,96 @@
+package com.persagy.dmp.file.controller;
+
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dmp.common.constant.ResponseCode;
+import com.persagy.dmp.common.constant.ValidEnum;
+import com.persagy.dmp.common.context.AppContext;
+import com.persagy.dmp.common.exception.BusinessException;
+import com.persagy.dmp.common.lang.PsDateTime;
+import com.persagy.dmp.common.model.response.CommonResult;
+import com.persagy.dmp.common.utils.ResultHelper;
+import com.persagy.dmp.file.domain.FileRequestData;
+import com.persagy.dmp.file.domain.UploadMes;
+import com.persagy.dmp.file.model.FileInfo;
+import com.persagy.dmp.file.model.FileMd5;
+import com.persagy.dmp.file.service.FileMd5Service;
+import com.persagy.dmp.file.service.IFileService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 文件管理Controller
+ * @author Charlie Yu
+ * @date 2021-05-15
+ */
+@RestController
+@RequestMapping("/file/md5")
+@RequiredArgsConstructor
+public class FileMd5Controller {
+
+    private final FileMd5Service fileMd5Service;
+
+    @PostMapping("/insert")
+    public CommonResult<FileMd5> insert(@RequestBody FileMd5 fileMd5) {
+        if(StrUtil.isBlank(fileMd5.getFileMd5())
+                || StrUtil.isBlank(fileMd5.getFileBucket())) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        fileMd5.setCreationTime(new PsDateTime());
+        fileMd5.setValid(ValidEnum.TRUE.getType());
+        fileMd5 = fileMd5Service.insertFileMd5(fileMd5);
+        return ResultHelper.single(fileMd5);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<FileMd5> update(@RequestBody FileMd5 fileMd5) {
+        if(StrUtil.isBlank(fileMd5.getId())
+                || StrUtil.isBlank(fileMd5.getFileMd5())) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        fileMd5.setModifiedTime(new PsDateTime());
+        fileMd5 = fileMd5Service.updateFileMd5(fileMd5);
+        return ResultHelper.single(fileMd5);
+    }
+
+    @PostMapping("/delete")
+    public CommonResult<String> delete(@RequestBody String id) {
+        if(StrUtil.isBlank(id)) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        FileMd5 fileMd5 = fileMd5Service.load(id);
+        if(fileMd5 == null) {
+            throw new BusinessException("找不到对应的文件信息");
+        }
+        fileMd5Service.deleteFileMd5(fileMd5);
+        return ResultHelper.success();
+    }
+
+    @PostMapping("/load")
+    public CommonResult<FileMd5> load(@RequestBody String id) {
+        if(StrUtil.isBlank(id)) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        FileMd5 fileMd5 = fileMd5Service.load(id);
+        if(fileMd5 == null) {
+            throw new BusinessException("找不到对应的文件信息");
+        }
+        return ResultHelper.single(fileMd5);
+    }
+
+    @PostMapping("/loadByMd5")
+    public CommonResult<FileMd5> loadByMd5(@RequestBody String md5) {
+        if(StrUtil.isBlank(md5)) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        FileMd5 fileMd5 = fileMd5Service.queryFileMd5ByFileMd5(md5);
+        if(fileMd5 == null) {
+            throw new BusinessException("找不到对应的文件信息");
+        }
+        return ResultHelper.single(fileMd5);
+    }
+
+
+
+}

+ 0 - 62
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileUploadController.java

@@ -1,62 +0,0 @@
-package com.persagy.dmp.file.controller;
-
-import cn.hutool.core.util.StrUtil;
-import com.persagy.dmp.common.constant.CommonConstant;
-import com.persagy.dmp.common.constant.ResponseCode;
-import com.persagy.dmp.common.constant.ValidEnum;
-import com.persagy.dmp.common.exception.BusinessException;
-import com.persagy.dmp.common.lang.PsDateTime;
-import com.persagy.dmp.common.model.response.CommonResult;
-import com.persagy.dmp.common.utils.ParamCheckUtil;
-import com.persagy.dmp.common.utils.ResultHelper;
-import com.persagy.dmp.file.domain.FileRequestData;
-import com.persagy.dmp.file.model.FileInfo;
-import com.persagy.dmp.file.service.FileUploadService;
-import com.persagy.dmp.file.service.IFileService;
-import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * 文件管理Controller
- * @author Charlie Yu
- * @date 2021-05-15
- */
-@RestController
-@RequestMapping("/upload/")
-@RequiredArgsConstructor(onConstructor = @__(@Autowired))
-@CrossOrigin(origins = "*",allowCredentials = "true",methods = {RequestMethod.POST,RequestMethod.GET},maxAge = 3600)
-public class FileUploadController {
-
-    private final FileUploadService fileUploadService;
-    /***
-     * Description: 初始化大文件上传
-     * @param requestData : 请求参数
-     * @return : com.persagy.dmp.common.model.response.CommonResult<com.persagy.dmp.file.model.FileInfo>  
-     * @author : lijie
-     * @date :2021/10/9 20:12
-     * Update By lijie 2021/10/9 20:12
-     */
-    @PostMapping("initChunkUpload")
-    public CommonResult<List<FileInfo>> initChunkUpload(@RequestBody FileRequestData requestData) {
-        //基础参数校验
-        ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE);
-        return ResultHelper.multi(fileUploadService.initChunkUpload(requestData));
-    }
-    /***
-     * Description: 初始化大文件上传
-     * @param requestData : 请求参数
-     * @return : com.persagy.dmp.common.model.response.CommonResult<com.persagy.dmp.file.model.FileInfo>
-     * @author : lijie
-     * @date :2021/10/9 20:12
-     * Update By lijie 2021/10/9 20:12
-     */
-    @PostMapping("composeFile")
-    public CommonResult<FileInfo> composeFile(@RequestBody FileRequestData requestData) {
-        //基础参数校验
-        ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE);
-        return ResultHelper.single(fileUploadService.composeFile(requestData));
-    }
-}

+ 16 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/dao/FileMd5Mapper.java

@@ -0,0 +1,16 @@
+package com.persagy.dmp.file.dao;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dmp.file.model.FileMd5;
+
+/**
+ * @Entity generator.domain.FileMd5
+ */
+public interface FileMd5Mapper extends BaseMapper<FileMd5> {
+
+}
+
+
+
+

+ 0 - 4
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/AccountDTO.java

@@ -1,4 +0,0 @@
-package com.persagy.dmp.file.domain;
-
-public class AccountDTO {
-}

+ 14 - 1
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/FileRequestData.java

@@ -1,9 +1,12 @@
 package com.persagy.dmp.file.domain;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.persagy.dmp.common.lang.PsDate;
 import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
 
 import java.io.Serializable;
+import java.util.Date;
 
 /***
  * Description: 文件请求参数
@@ -17,8 +20,11 @@ public class FileRequestData implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
+    /**上传方式,0-直接上传,1-分片上传*/
+    private String uploadFlag;
+
     /**存储桶名称*/
-    private String bucketName;
+    private String fileBucket;
 
     /**分片数量*/
     private Integer chunkCount;
@@ -32,6 +38,9 @@ public class FileRequestData implements Serializable {
     /**文件名称*/
     private String fileName;
 
+    /**文件大小*/
+    private Long fileSize;
+
     /**文件地址*/
     private String filePath;
 
@@ -50,4 +59,8 @@ public class FileRequestData implements Serializable {
     /**业务id*/
     private String businessId;
 
+    /**过期时间,入参格式为yyyyMMddHHmmss*/
+    @DateTimeFormat(pattern = "yyyyMMddHHmmss")
+    private PsDate expireDate;
+
 }

+ 19 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/UploadMes.java

@@ -0,0 +1,19 @@
+package com.persagy.dmp.file.domain;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+
+@Data
+@EqualsAndHashCode
+@ToString
+public class UploadMes {
+    /**文件id*/
+    private String fileId;
+    /**文件上传成功code,200-秒传,201-单个文件上传,202-断点续传且文件分片均已上传,203-断点续传*/
+    private Integer uploadCode;
+    /**文件上传信息*/
+    private List<UploadSubMes> content;
+}

+ 15 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/UploadSubMes.java

@@ -0,0 +1,15 @@
+package com.persagy.dmp.file.domain;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@EqualsAndHashCode
+@ToString
+public class UploadSubMes {
+    /**分片的序号*/
+    private Integer partNumber;
+    /**分片的上传URL*/
+    private String uploadUrl;
+}

+ 66 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/FileMd5Service.java

@@ -0,0 +1,66 @@
+package com.persagy.dmp.file.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.persagy.dmp.file.model.FileMd5;
+
+/**
+ *
+ */
+public interface FileMd5Service extends IService<FileMd5> {
+    /***
+     * Description: 插入数据
+     * @param fileMd5 : 请求参数
+     * @return : com.persagy.dmp.file.model.FileMd5
+     * @author : lijie
+     * @date :2021/10/22 21:32
+     * Update By lijie 2021/10/22 21:32
+     */
+    FileMd5 insertFileMd5(FileMd5 fileMd5);
+    /***
+     * Description: 确定文件上传路径
+     * @param fileMd5 : 文件信息
+     * @param fileName : 文件名称
+     * @param groupCode : 集团编码
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/22 21:46
+     * Update By lijie 2021/10/22 21:46
+     */
+    void ensureFilePath(FileMd5 fileMd5, String fileName, String groupCode);
+    /***
+     * Description: 根据文件md5值查询文件Md5信息
+     * @param fileMd5 : 文件的md5值
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/22 21:46
+     * Update By lijie 2021/10/22 21:46
+     */
+    FileMd5 queryFileMd5ByFileMd5(String fileMd5);
+    /***
+     * Description: 更新文件MD5信息
+     * @param fileMd5 : 文件MD5信息
+     * @return : com.persagy.dmp.file.model.FileMd5
+     * @author : lijie
+     * @date :2021/10/22 21:47
+     * Update By lijie 2021/10/22 21:47
+     */
+    FileMd5 updateFileMd5(FileMd5 fileMd5);
+    /***
+     * Description: 根据文件id查询文件MD5信息
+     * @param id : 主键
+     * @return : com.persagy.dmp.file.model.FileMd5
+     * @author : lijie
+     * @date :2021/10/22 21:50
+     * Update By lijie 2021/10/22 21:50
+     */
+    FileMd5 load(String id);
+    /***
+     * Description: 逻辑删除文件Md5
+     * @param fileMd5 : 文件Md5信息
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/22 22:02
+     * Update By lijie 2021/10/22 22:02
+     */
+    void deleteFileMd5(FileMd5 fileMd5);
+}

+ 0 - 34
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/FileUploadService.java

@@ -1,34 +0,0 @@
-package com.persagy.dmp.file.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.persagy.dmp.file.domain.FileRequestData;
-import com.persagy.dmp.file.model.FileInfo;
-
-import java.util.List;
-
-/***
- * Description: 文件上传处理逻辑
- * @author : lijie
- * @date :2021/10/9 20:09
- * Update By lijie 2021/10/9 20:09
- */
-public interface FileUploadService extends IService<FileInfo> {
-    /***
-     * 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
-     */
-    List<FileInfo> initChunkUpload(FileRequestData 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
-     */
-    FileInfo composeFile(FileRequestData requestData);
-}

+ 39 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/IFileService.java

@@ -1,5 +1,7 @@
 package com.persagy.dmp.file.service;
 
+import com.persagy.dmp.file.domain.FileRequestData;
+import com.persagy.dmp.file.domain.UploadMes;
 import com.persagy.dmp.file.model.FileInfo;
 
 import java.util.List;
@@ -51,4 +53,41 @@ public interface IFileService {
      * @return
      */
     List<FileInfo> queryByBusinessId(String businessId);
+
+    /***
+     * 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
+     */
+    UploadMes initChunkUpload(FileRequestData 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
+     */
+    FileInfo composeFile(FileRequestData requestData);
+    /***
+     * 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
+     */
+    UploadMes initSingleUpload(FileRequestData requestData);
+    /***
+     * 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
+     */
+    List<FileInfo> queryByFileMd5(String fileMd5);
 }

+ 138 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileMd5ServiceImpl.java

@@ -0,0 +1,138 @@
+package com.persagy.dmp.file.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
+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.ValidEnum;
+import com.persagy.dmp.common.lang.PsDateTime;
+import com.persagy.dmp.file.dao.FileMd5Mapper;
+import com.persagy.dmp.file.model.FileInfo;
+import com.persagy.dmp.file.model.FileMd5;
+import com.persagy.dmp.file.model.FileMd5Creator;
+import com.persagy.dmp.file.service.FileMd5Service;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ *
+ */
+@Service
+public class FileMd5ServiceImpl extends ServiceImpl<FileMd5Mapper, FileMd5> implements FileMd5Service {
+    /***
+     * Description: 插入文件Md5
+     * @param fileMd5 : 文件请求信息
+     * @return : com.persagy.dmp.file.model.FileMd5
+     * @author : lijie
+     * @date :2021/10/22 21:41
+     * Update By lijie 2021/10/22 21:41
+     */
+    @Override
+    public FileMd5 insertFileMd5(FileMd5 fileMd5) {
+        ensureFilePath(fileMd5,fileMd5.getFileName(),fileMd5.getGroupCode());
+        this.save(fileMd5);
+        return fileMd5;
+    }
+
+    /**
+     * 确认文件名称
+     * @param vo 文件管理对象
+     * @return
+     */
+    @Override
+    public void ensureFilePath(FileMd5 vo, String fileName, String groupCode) {
+        // 组装文件路径 - 日期以文件创建日期为准
+        FileMd5Creator.buildFilePath(vo,fileName,groupCode);
+        // 是否存在同名
+        LambdaQueryWrapper<FileMd5> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(FileMd5::getValid, ValidEnum.TRUE.getType()).
+                eq(FileMd5::getFilePath, vo.getFilePath());
+        if(StrUtil.isNotBlank(vo.getId())) {
+            queryWrapper.ne(FileMd5::getId, vo.getId());
+        }
+        List<FileMd5> dbVos = this.list(queryWrapper);
+        if(CollUtil.isEmpty(dbVos)) {
+            return;
+        }
+        // 存在同名 - 重新命名 +随机数
+        String resetFileName = resetFileName(fileName);
+        ensureFilePath(vo,resetFileName,groupCode);
+    }
+
+    /***
+     * Description: 根据文件md5查询文件信息
+     * @param fileMd5 : 文件md5值
+     * @return : java.util.List<com.persagy.dmp.file.model.FileInfo>
+     * @author : lijie
+     * @date :2021/10/9 20:32
+     * Update By lijie 2021/10/9 20:32
+     */
+    @Override
+    public FileMd5 queryFileMd5ByFileMd5(String fileMd5) {
+        LambdaQueryWrapper<FileMd5> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(FileMd5::getFileMd5,fileMd5);
+        queryWrapper.eq(FileMd5::getValid,true);
+        return this.getOne(queryWrapper);
+    }
+    /***
+     * Description: 更新文件MD5信息
+     * @param fileMd5 : 文件MD5信息
+     * @return : com.persagy.dmp.file.model.FileMd5
+     * @author : lijie
+     * @date :2021/10/22 21:50
+     * Update By lijie 2021/10/22 21:50
+     */
+    @Override
+    public FileMd5 updateFileMd5(FileMd5 fileMd5) {
+        FileMd5 dbVO = load(fileMd5.getId());
+        fileMd5.setCreationTime(dbVO.getCreationTime());
+        fileMd5.setModifiedTime(new PsDateTime());
+        updateById(fileMd5);
+        return fileMd5;
+    }
+    /***
+     * Description: 根据文件id查询文件MD5信息
+     * @param id : 主键
+     * @return : com.persagy.dmp.file.model.FileMd5
+     * @author : lijie
+     * @date :2021/10/22 21:50
+     * Update By lijie 2021/10/22 21:50
+     */
+    @Override
+    public FileMd5 load(String id) {
+        return getById(id);
+    }
+    /***
+     * Description: 逻辑删除文件Md5
+     * @param fileMd5 : 文件Md5信息
+     * @return : void
+     * @author : lijie
+     * @date :2021/10/22 22:02
+     * Update By lijie 2021/10/22 22:02
+     */
+    @Override
+    public void deleteFileMd5(FileMd5 fileMd5) {
+        fileMd5.setValid(ValidEnum.FALSE.getType());
+        updateFileMd5(fileMd5);
+    }
+
+    /**
+     * 重命名
+     * @param oldFileName 原文件名
+     * @return 原文件名前缀+"-随机数"+后缀
+     */
+    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();
+    }
+}
+
+
+
+

+ 232 - 33
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileServiceImpl.java

@@ -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;
     }
+
 }

+ 0 - 175
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileUploadServiceImpl.java

@@ -1,175 +0,0 @@
-package com.persagy.dmp.file.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.api.R;
-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.model.response.CommonResult;
-import com.persagy.dmp.common.utils.ResultHelper;
-import com.persagy.dmp.file.dao.FileMapper;
-import com.persagy.dmp.file.domain.FileRequestData;
-import com.persagy.dmp.file.model.FileInfo;
-import com.persagy.dmp.file.model.FileInfoCreator;
-import com.persagy.dmp.file.service.FileUploadService;
-import com.persagy.dmp.storage.service.MinioCommonService;
-import lombok.RequiredArgsConstructor;
-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.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/***
- * Description: 文件上传逻辑处理类
- * @author : lijie
- * @date :2021/10/9 20:09
- * Update By lijie 2021/10/9 20:09
- */
-@Service
-@RequiredArgsConstructor(onConstructor = @__(@Autowired))
-@Slf4j
-public class FileUploadServiceImpl extends ServiceImpl<FileMapper, FileInfo> implements FileUploadService {
-
-   private final MinioCommonService minioCommonService;
-
-    /**上传成功*/
-    private static final Integer UPLOAD_SUCCESS = 0;
-
-    /**部分上传*/
-    private static final Integer UPLOAD_PART = 1;
-
-    /***
-     * 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
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public List<FileInfo> initChunkUpload(FileRequestData requestData) {
-        String groupCode = AppContext.getContext().getGroupCode();
-        requestData.setGroupCode(groupCode);
-        if (StrUtil.isBlank(requestData.getFileMd5())){
-            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
-        }
-        // 1.根据文件md5值查询数据库
-        FileInfo fileInfo = queryFileInfosByFileMd5(requestData.getFileMd5());
-        // 2.历史已上传且已完成上传
-        if (ObjectUtil.isNotNull(fileInfo)
-                && UPLOAD_SUCCESS.equals(fileInfo.getUploadStatus())){
-            return CollUtil.newArrayList(fileInfo);
-        }
-        // 3.历史已上传
-        //获取到该文件已上传分片
-        Map<Integer,String> okChunkMap = minioCommonService.mapChunkObjectNames(requestData.getBucketName(),
-                requestData.getFileMd5());
-        List<FileInfo> chunkUploadUrls = new ArrayList<>();
-        if (okChunkMap.size() > 0){
-            for (int i = 1; i <= requestData.getChunkCount(); i++) {
-                //判断当前分片是否已经上传过了
-                if(okChunkMap.containsKey(i)){
-                    continue;
-                }
-                //生成分片上传url
-                FileInfo url = new FileInfo();
-                url.setPartNumber(i);
-                url.setUploadUrl(minioCommonService.createUploadChunkUrl(requestData.getBucketName(),
-                        requestData.getFileMd5(),i));
-                chunkUploadUrls.add(url);
-            }
-            if (chunkUploadUrls.size() == 0){
-                return new ArrayList<>();
-            }
-            return chunkUploadUrls;
-        }
-        // 4.第一次上传或已存在但没有上传过分片的
-        return firstInitChunkUploadInternal(requestData);
-    }
-
-    @Override
-    public FileInfo composeFile(FileRequestData requestData) {
-        //根据md5获取所有分片文件名称(minio的文件名称 = 文件path)
-        List<String> chunks = minioCommonService
-                .listObjectNames(minioCommonService.getChuckBucketName(null),requestData.getFileMd5());
-        if (CollUtil.isEmpty(chunks)){
-            throw new BusinessException(ResponseCode.A0400.getCode(), "分片文件数量为空");
-        }
-        //获取数据库里记录的文件信息,修改数据并返回文件信息
-        FileInfo fileInfo = queryFileInfosByFileMd5(requestData.getFileMd5());
-        if (null==fileInfo){
-            throw new BusinessException(ResponseCode.A0400.getCode(), "文件信息为空");
-        }
-        //自定义文件名称
-        String fileName = requestData.getFileName();
-        String suffix = fileName.substring(fileName.lastIndexOf("."));
-        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
-        fileName = df.format(LocalDateTime.now()) + suffix;
-        //合并文件
-        if(minioCommonService.composeObject(requestData.getBucketName(),chunks,fileName)){
-            //获取文件访问外链(1小时过期)
-            String url = minioCommonService.getObjectUrl(requestData.getBucketName(),fileName,60);
-            fileInfo.setUploadStatus(UPLOAD_SUCCESS);
-            fileInfo.setFileName(fileName);
-            fileInfo.setFilePath(url);
-            this.updateById(fileInfo);
-            return fileInfo;
-        }
-        throw new BusinessException(ResponseCode.B0001.getCode(), "合并文件失败");
-    }
-
-    /***
-     * 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 List<FileInfo> firstInitChunkUploadInternal(FileRequestData requestData) {
-        List<String> uploadUrls = minioCommonService.createUploadChunkUrlList(requestData.getBucketName(),
-                requestData.getFileMd5(),
-                requestData.getChunkCount());
-        List<FileInfo> chunkUploadUrls = new ArrayList<>();
-        for (int i = 1; i <= uploadUrls.size(); i++) {
-            FileInfo fileInfo = new FileInfo();
-            fileInfo.setPartNumber(i);
-            fileInfo.setUploadUrl(minioCommonService.createUploadChunkUrl(requestData.getBucketName(),
-                    requestData.getFileMd5(),i));
-            chunkUploadUrls.add(fileInfo);
-        }
-        //向数据库中记录该文件的上传信息
-        FileInfo fileInfo = FileInfoCreator.of(AppContext.getContext().getGroupCode(),requestData.getBusinessId(),
-                requestData.getBucketName(), requestData.getFileName());
-        fileInfo.setUploadStatus(UPLOAD_PART);
-        fileInfo.setFileMd5(requestData.getFileMd5());
-        this.save(fileInfo);
-        return chunkUploadUrls;
-    }
-
-    /***
-     * Description: 根据文件md5查询文件信息
-     * @param fileMd5 : 文件md5值
-     * @return : java.util.List<com.persagy.dmp.file.model.FileInfo>
-     * @author : lijie
-     * @date :2021/10/9 20:32
-     * Update By lijie 2021/10/9 20:32
-     */
-    private FileInfo queryFileInfosByFileMd5(String fileMd5) {
-        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(FileInfo::getFileMd5,fileMd5);
-        queryWrapper.eq(FileInfo::getValid,true);
-        return this.getOne(queryWrapper);
-    }
-}

+ 15 - 3
dmp-cloud/dmp-file/src/main/resources/db/init/schema.sql

@@ -2,14 +2,25 @@ CREATE TABLE IF NOT EXISTS `dt_file_info` (
 `id` varchar(40) NOT NULL COMMENT '主键',
 `group_code` varchar(40) NOT NULL COMMENT '集团编码',
 `file_name` varchar(128) NOT NULL COMMENT '文件名称',
+`business_id` varchar(32) NULL DEFAULT NULL COMMENT '关联业务Id',
+`expire_date` char(8) NULL DEFAULT NULL COMMENT '保留期限',
+`creator` varchar(32) DEFAULT NULL COMMENT '创建人',
+`creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
+`modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
+`modified_time` char(14) NULL DEFAULT NULL COMMENT '最后修改时间',
+`valid` tinyint DEFAULT 1 COMMENT '合法标识',
+`ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
+PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='文件信息';
+
+CREATE TABLE IF NOT EXISTS `dt_file_md5` (
+`id` varchar(40) NOT NULL COMMENT '主键',
 `file_type` varchar(2) NOT NULL DEFAULT '0' COMMENT '文件类型:0-文件,1-目录',
 `file_bucket` varchar(64) NOT NULL DEFAULT '0' COMMENT '文件分组:默认为应用名',
 `file_path` varchar(512) NULL DEFAULT NULL COMMENT '文件路径含文件名称-对应文件存储路径',
 `file_size` int(10) NOT NULL DEFAULT 0 COMMENT '文件大小',
 `file_md5` varchar(64) NULL DEFAULT NULL COMMENT '文件的md5值',
 `upload_status` tinyint NOT NULL DEFAULT 0 COMMENT '文件上传状态,0.上传完成,1.已上传部分',
-`business_id` varchar(32) NULL DEFAULT NULL COMMENT '关联业务Id',
-`expire_date` char(8) NULL DEFAULT NULL COMMENT '保留期限',
 `creator` varchar(32) DEFAULT NULL COMMENT '创建人',
 `creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
 `modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
@@ -17,4 +28,5 @@ CREATE TABLE IF NOT EXISTS `dt_file_info` (
 `valid` tinyint DEFAULT 1 COMMENT '合法标识',
 `ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
 PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='文件信息';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='文件的MD5信息';
+

+ 11 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileClientFacade.java

@@ -5,6 +5,8 @@ import com.persagy.dmp.file.model.FileInfo;
 import com.persagy.dmp.common.model.response.CommonResult;
 import com.persagy.dmp.common.utils.ResultHelper;
 
+import java.util.List;
+
 /**
  * 文件管理Client门面
  * @author Charlie Yu
@@ -52,4 +54,13 @@ public class FileClientFacade {
         CommonResult<FileInfo> result = client.load(fileId);
         return ResultHelper.getContent(result);
     }
+    /**
+     * 查询
+     * @param fileMd5
+     * @return
+     */
+    public static List<FileInfo> queryByFileMd5(String fileMd5) {
+        CommonResult<List<FileInfo>> result = client.queryByFileMd5(fileMd5);
+        return ResultHelper.getContent(result);
+    }
 }

+ 14 - 5
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileManageClient.java

@@ -7,12 +7,14 @@ import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 
+import java.util.List;
+
 /**
  * 文件管理Client
  * @author Charlie Yu
  * @date 2021-05-15
  */
-@FeignClient(name = "dmp-file", configuration = FileFeignConfig.class)
+@FeignClient(name = "dmp-file", configuration = FileFeignConfig.class,path = "/file/",url = "${persagy.bdtp.file.service:}")
 public interface FileManageClient {
 
     /**
@@ -20,7 +22,7 @@ public interface FileManageClient {
      * @param fileInfo 文件信息
      * @return 文件信息
      */
-    @PostMapping("/file/insert")
+    @PostMapping("insert")
     CommonResult<FileInfo> insert(@RequestBody FileInfo fileInfo);
 
     /**
@@ -28,7 +30,7 @@ public interface FileManageClient {
      * @param fileInfo 文件信息
      * @return 文件信息
      */
-    @PostMapping("/file/update")
+    @PostMapping("update")
     CommonResult<FileInfo> update(@RequestBody FileInfo fileInfo);
 
     /**
@@ -36,7 +38,7 @@ public interface FileManageClient {
      * @param id 文件信息
      * @return 文件信息
      */
-    @PostMapping("/file/delete")
+    @PostMapping("delete")
     CommonResult<String> delete(@RequestBody String id);
 
     /**
@@ -44,6 +46,13 @@ public interface FileManageClient {
      * @param id 文件信息
      * @return 文件信息
      */
-    @PostMapping("/file/load")
+    @PostMapping("load")
     CommonResult<FileInfo> load(@RequestBody String id);
+    /**
+     * 查询文件信息
+     * @param id 文件信息
+     * @return 文件信息
+     */
+    @PostMapping("queryByFileMd5")
+    CommonResult<List<FileInfo>> queryByFileMd5(@RequestBody String id);
 }

+ 57 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileMd5Client.java

@@ -0,0 +1,57 @@
+package com.persagy.dmp.file.client;
+
+import com.persagy.dmp.common.model.response.CommonResult;
+import com.persagy.dmp.file.model.FileInfo;
+import com.persagy.dmp.file.model.FileMd5;
+import com.persagy.dmp.storage.config.FileFeignConfig;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * 文件管理Client
+ * @author Charlie Yu
+ * @date 2021-05-15
+ */
+@FeignClient(name = "dmp-file", configuration = FileFeignConfig.class,path = "/file/md5/",url = "${persagy.bdtp.file.service:}")
+public interface FileMd5Client {
+
+    /**
+     * 新增文件MD5信息
+     * @param fileMd5 文件MD5信息
+     * @return 文件MD5信息
+     */
+    @PostMapping("insert")
+    CommonResult<FileMd5> insert(@RequestBody FileMd5 fileMd5);
+
+    /**
+     * 修改文件MD5信息
+     * @param fileMd5 MD5信息
+     * @return MD5信息
+     */
+    @PostMapping("update")
+    CommonResult<FileMd5> update(@RequestBody FileMd5 fileMd5);
+
+    /**
+     * 删除文件MD5信息
+     * @param id 文件MD5信息
+     * @return 文件MD5信息
+     */
+    @PostMapping("delete")
+    CommonResult<String> delete(@RequestBody String id);
+
+    /**
+     * 查询文件MD5信息
+     * @param id 文件MD5信息
+     * @return 文件MD5信息
+     */
+    @PostMapping("load")
+    CommonResult<FileMd5> load(@RequestBody String id);
+    /**
+     * 查询文件MD5信息
+     * @param md5 文件的md5
+     * @return 文件MD5信息
+     */
+    @PostMapping("loadByMd5")
+    CommonResult<FileMd5> loadByMd5(@RequestBody String md5);
+}

+ 65 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileMd5ClientFacade.java

@@ -0,0 +1,65 @@
+package com.persagy.dmp.file.client;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.persagy.dmp.common.model.response.CommonResult;
+import com.persagy.dmp.common.utils.ResultHelper;
+import com.persagy.dmp.file.model.FileInfo;
+import com.persagy.dmp.file.model.FileMd5;
+
+/**
+ * 文件管理Client门面
+ * @author Charlie Yu
+ * @date 2021-05-15
+ */
+public class FileMd5ClientFacade {
+
+    private static FileMd5Client client = SpringUtil.getBean(FileMd5Client.class);
+
+    /**
+     * 新增
+     * @param fileMd5
+     * @return
+     */
+    public static FileMd5 insert(FileMd5 fileMd5) {
+        CommonResult<FileMd5> result = client.insert(fileMd5);
+        return ResultHelper.getContent(result);
+    }
+
+    /**
+     * 修改
+     * @param fileMd5
+     * @return
+     */
+    public static FileMd5 update(FileMd5 fileMd5) {
+        CommonResult<FileMd5> result = client.update(fileMd5);
+        return ResultHelper.getContent(result);
+    }
+
+    /**
+     * 删除
+     * @param fileId
+     */
+    public static void delete(String fileId) {
+        CommonResult<String> result = client.delete(fileId);
+        ResultHelper.getContent(result);
+    }
+
+    /**
+     * 查询
+     * @param fileId
+     * @return
+     */
+    public static FileMd5 load(String fileId) {
+        CommonResult<FileMd5> result = client.load(fileId);
+        return ResultHelper.getContent(result);
+    }
+    /**
+     * 查询
+     * @param fileMd5
+     * @return
+     */
+    public static FileMd5 loadByMd5(String fileMd5) {
+        CommonResult<FileMd5> result = client.loadByMd5(fileMd5);
+        return ResultHelper.getContent(result);
+    }
+}

+ 5 - 6
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileInfo.java

@@ -22,25 +22,24 @@ public class FileInfo extends AuditableEntity<FileInfo> {
     /** 文件名称:显示用 */
     private String fileName;
     /** 文件类型:0-文件,1-目录 */
+    @TableField(exist = false)
     private String fileType;
     /** 文件分组:默认为应用名 */
+    @TableField(exist = false)
     private String fileBucket;
     /** 文件路径:含文件名称 - 对应文件存储路径 */
+    @TableField(exist = false)
     private String filePath;
     /** 文件大小 */
+    @TableField(exist = false)
     private Long fileSize;
     /** 文件的md5值 */
     private String fileMd5;
     /** 文件上传状态,0.上传完成 1.已上传部分 */
+    @TableField(exist = false)
     private Integer uploadStatus;
     /** 关联业务Id */
     private String businessId;
     /** 保留期限 */
     private PsDate expireDate;
-    /** 分片序号 */
-    @TableField(exist = false)
-    private Integer partNumber;
-    /** 上传地址 */
-    @TableField(exist = false)
-    private String uploadUrl;
 }

+ 19 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileInfoCreator.java

@@ -7,6 +7,8 @@ import com.persagy.dmp.common.exception.BusinessException;
 import com.persagy.dmp.common.lang.PsDate;
 import com.persagy.dmp.storage.constant.FileCommonConst;
 
+import java.util.Date;
+
 /**
  * 文件信息组装器
  * @author Charlie Yu
@@ -34,6 +36,23 @@ public class FileInfoCreator {
         fileInfo.setBusinessId(businessId);
         return fileInfo;
     }
+    /**
+     * 创建FileInfo
+     * @param groupCode 集团编码 - 租户
+     * @param businessId 业务Id
+     * @param fileName 文件名
+     * @return
+     */
+    public static FileInfo of(String groupCode, String fileName, String businessId, String fileMd5, PsDate expireDate){
+        FileInfo fileInfo = new FileInfo();
+        fileInfo.setGroupCode(groupCode);
+        fileInfo.setFileName(fileName);
+        fileInfo.setBusinessId(businessId);
+        fileInfo.setFileMd5(fileMd5);
+        fileInfo.setExpireDate(expireDate);
+        fileInfo.setValid(1);
+        return fileInfo;
+    }
 
     /**
      * 桶名处理

+ 65 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileMd5.java

@@ -0,0 +1,65 @@
+package com.persagy.dmp.file.model;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dmp.common.model.entity.AuditableEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+/**
+ * 文件的MD5信息
+ * @TableName dt_file_md5
+ */
+@TableName(value ="dt_file_md5")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString
+public class FileMd5 extends AuditableEntity<FileMd5> {
+
+    /**
+     * 文件类型:0-文件,1-目录
+     */
+    @TableField(value = "file_type")
+    private String fileType;
+
+    /**
+     * 文件分组:默认为应用名
+     */
+    @TableField(value = "file_bucket")
+    private String fileBucket;
+
+    /**
+     * 文件路径含文件名称-对应文件存储路径
+     */
+    @TableField(value = "file_path")
+    private String filePath;
+
+    /**
+     * 文件大小
+     */
+    @TableField(value = "file_size")
+    private Long fileSize;
+
+    /**
+     * 文件的md5值
+     */
+    @TableField(value = "file_md5")
+    private String fileMd5;
+
+    /**
+     * 文件上传状态,0.上传完成,1.已上传部分
+     */
+    @TableField(value = "upload_status")
+    private Integer uploadStatus;
+    /**
+     * 文件名称
+     */
+    @TableField(exist = false)
+    private String fileName;
+    /**
+     * 集团编码
+     */
+    @TableField(exist = false)
+    private String groupCode;
+}

+ 44 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileMd5Creator.java

@@ -0,0 +1,44 @@
+package com.persagy.dmp.file.model;
+
+import cn.hutool.core.io.file.FileNameUtil;
+import cn.hutool.core.util.ReUtil;
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dmp.common.exception.BusinessException;
+import com.persagy.dmp.common.lang.PsDate;
+import com.persagy.dmp.storage.constant.FileCommonConst;
+
+/***
+ * Description: 文件信息组装器
+ * @author : lijie
+ * @date :2021/10/22 15:00
+ * Update By lijie 2021/10/22 15:00
+ */
+public class FileMd5Creator {
+
+    /**
+     * 创建FileInfo
+     * @param bucketName 桶 - 应用名
+     * @return
+     */
+    public static FileMd5 of(String bucketName, String fileMd5Str,Integer uploadStatus){
+        FileMd5 fileMd5 = new FileMd5();
+        fileMd5.setFileBucket(FileInfoCreator.formatBucket(bucketName));
+        fileMd5.setFileMd5(fileMd5Str);
+        fileMd5.setFileType("0");
+        fileMd5.setUploadStatus(uploadStatus);
+        fileMd5.setValid(1);
+        return fileMd5;
+    }
+
+    /**
+     * 组装文件路径
+     * groupCode/dateStr/fileName
+     * @param fileMd5 文件管理信息
+     */
+    public static void buildFilePath(FileMd5 fileMd5,String fileName,String groupCode) {
+        String date = PsDate.parsePsDate(fileMd5.getCreationTime()).toString();
+        String sb = groupCode + FileNameUtil.UNIX_SEPARATOR + date +
+                FileNameUtil.UNIX_SEPARATOR + fileName;
+        fileMd5.setFilePath(sb);
+    }
+}

+ 0 - 9
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/config/MinioConfig.java

@@ -1,13 +1,10 @@
 package com.persagy.dmp.storage.config;
 
 import com.persagy.dmp.storage.service.IFileStorageService;
-import com.persagy.dmp.storage.service.MinioCommonService;
-import com.persagy.dmp.storage.service.impl.MinioCommonServiceImpl;
 import com.persagy.dmp.storage.service.impl.MinioStorageServiceImpl;
 import io.minio.MinioClient;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
@@ -42,10 +39,4 @@ public class MinioConfig {
     public IFileStorageService minioStorageServiceImpl() {
         return new MinioStorageServiceImpl(minioClient());
     }
-
-    @Bean
-    @ConditionalOnProperty(value = "persagy.common.file.storage", havingValue = "0")
-    public MinioCommonService minioCommonService() {
-        return new MinioCommonServiceImpl(minioClient());
-    }
 }

+ 5 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/constant/FileCommonConst.java

@@ -11,4 +11,9 @@ public interface FileCommonConst {
     String DEFAULT_BUCKET = "default";
     /** 链接有效期(秒):7天 */
     int URL_EXPIRES = 7 * 24 * 3600;
+    /**上传成功*/
+    Integer UPLOAD_SUCCESS = 0;
+
+    /**部分上传*/
+    Integer UPLOAD_PART = 1;
 }

+ 166 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/IFileStorageService.java

@@ -1,6 +1,12 @@
 package com.persagy.dmp.storage.service;
 
+import lombok.SneakyThrows;
+
+import javax.swing.filechooser.FileView;
 import java.io.InputStream;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 文件存储服务接口
@@ -53,4 +59,164 @@ public interface IFileStorageService {
      * @param bucketName 桶名
      */
     void deletePath(String bucketName);
+
+    /***
+     * Description: 存储桶是否存在
+     * @param bucketName: 存储桶名称
+     * @return true/false
+     * @author : lijie
+     * @date :2021/10/16 14:35
+     * Update By lijie 2021/10/16 14:35
+     */
+    boolean isBucketExist(String bucketName);
+
+    /***
+     * Description:  创建存储桶
+     * @param bucketName : 存储桶名称
+     * @return : true/false
+     * @author : lijie
+     * @date :2021/10/16 14:35
+     * Update By lijie 2021/10/16 14:35
+     */
+    boolean createBucket(String bucketName);
+
+    /***
+     * Description: 获取访问对象的外链地址
+     * @param bucketName : 存储桶名称
+     * @param objectName : 对象名称
+     * @param expiry : 过期时间(分钟) 最大为7天 超过7天则默认最大值
+     * @return : viewUrl
+     * @author : lijie
+     * @date :2021/10/16 14:41
+     * Update By lijie 2021/10/16 14:41
+     */
+    String getObjectUrl(String bucketName, String objectName, Integer expiry);
+
+    /***
+     * Description: 创建上传文件对象的外链
+     * @param bucketName : 存储桶名称
+     * @param objectName : 欲上传文件对象的名称
+     * @param expiry : 过期时间(分钟) 最大为7天 超过7天则默认最大值
+     * @return : uploadUrl
+     * @author : lijie
+     * @date :2021/10/16 14:41
+     * Update By lijie 2021/10/16 14:41
+     */
+    String createUploadUrl(String bucketName, String objectName, Integer expiry);
+
+    /***
+     * Description: 创建上传文件对象的外链
+     * @param bucketName : 存储桶名称
+     * @param objectName : 欲上传文件对象的名称
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/10/16 14:42
+     * Update By lijie 2021/10/16 14:42
+     */
+    String createUploadUrl(String bucketName, String objectName);
+    /***
+     * Description: 批量创建分片上传外链
+     * @param bucketName : 存储桶名称
+     * @param objectMD5 : 欲上传分片文件主文件的MD5
+     * @param chunkCount : 分片数量
+     * @return : uploadChunkUrls
+     * @author : lijie
+     * @date :2021/10/16 14:43
+     * Update By lijie 2021/10/16 14:43
+     */
+    List<String> createUploadChunkUrlList(String bucketName, String objectMD5, Integer chunkCount);
+
+    /***
+     * Description: 创建指定序号的分片文件上传外链
+     * @param bucketName : 存储桶名称
+     * @param objectMD5 : 欲上传分片文件主文件的MD5
+     * @param partNumber : 分片序号
+     * @return : uploadChunkUrl
+     * @author : lijie
+     * @date :2021/10/16 14:44
+     * Update By lijie 2021/10/16 14:44
+     */
+    String createUploadChunkUrl(String bucketName, String objectMD5, Integer partNumber);
+
+    /***
+     * Description: 获取对象文件名称列表
+     * @param bucketName : 存储桶名称
+     * @param prefix : 对象名称前缀
+     * @param sort : 是否排序(升序)
+     * @return : objectNames
+     * @author : lijie
+     * @date :2021/10/16 14:45
+     * Update By lijie 2021/10/16 14:45
+     */
+    List<String> listObjectNames(String bucketName, String prefix, Boolean sort);
+
+    /***
+     * Description: 获取对象文件名称列表
+     * @param bucketName : 存储桶名称
+     * @param prefix : 对象名称前缀
+     * @return : objectNames
+     * @author : lijie
+     * @date :2021/10/16 14:47
+     * Update By lijie 2021/10/16 14:47
+     */
+    List<String> listObjectNames(String bucketName, String prefix);
+
+    /***
+     * Description: 获取分片文件名称列表
+     * @param bucketName : 存储桶名称
+     * @param ObjectMd5 : 对象Md5
+     * @return : objectChunkNames
+     * @author : lijie
+     * @date :2021/10/16 14:48
+     * Update By lijie 2021/10/16 14:48
+     */
+    List<String> listChunkObjectNames(String bucketName, String ObjectMd5);
+
+    /***
+     * Description: 获取分片名称地址HashMap key=分片序号 value=分片文件地址
+     * @param bucketName : 存储桶名称
+     * @param ObjectMd5 : 对象Md5
+     * @return : objectChunkNameMap
+     * @author : lijie
+     * @date :2021/10/16 14:49
+     * Update By lijie 2021/10/16 14:49
+     */
+    Map<Integer, String> mapChunkObjectNames(String bucketName, String ObjectMd5);
+
+    /***
+     * Description: 合并分片文件成对象文件
+     * @param chunkBucKetName : 分片文件所在存储桶名称
+     * @param composeBucketName : 合并后的对象文件存储的存储桶名称
+     * @param chunkNames : 分片文件名称集合
+     * @param objectName : 合并后的对象文件名称
+     * @return : boolean
+     * @author : lijie
+     * @date :2021/10/16 14:50
+     * Update By lijie 2021/10/16 14:50
+     */
+    boolean composeObject(String chunkBucKetName, String composeBucketName, List<String> chunkNames, String objectName);
+
+    /***
+     * Description: 合并分片文件成对象文件
+     * @param bucketName : 存储桶名称
+     * @param chunkNames : 分片文件名称集合
+     * @param objectName : 合并后的对象文件名称
+     * @return : true/false
+     * @author : lijie
+     * @date :2021/10/16 14:51
+     * Update By lijie 2021/10/16 14:51
+     */
+    boolean composeObject(String bucketName, List<String> chunkNames, String objectName);
+    /***
+     * Description: 获取chuck的bucketName
+     * @param bucketName : 传入的bucketName
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/10/21 10:39
+     * Update By lijie 2021/10/21 10:39
+     */
+    String getChuckBucketName(String bucketName);
+
+    @SneakyThrows
+    Long getObjectSize(String bucketName, String objectName);
 }

+ 0 - 171
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/MinioCommonService.java

@@ -1,171 +0,0 @@
-package com.persagy.dmp.storage.service;
-
-import lombok.SneakyThrows;
-
-import java.util.List;
-import java.util.Map;
-
-/***
- * Description: minio通用操作处理类
- * @author : lijie
- * @date :2021/10/16 14:27
- * Update By lijie 2021/10/16 14:27
- */
-public interface MinioCommonService {
-    /***
-     * Description: 存储桶是否存在
-     * @param bucketName: 存储桶名称
-     * @return true/false
-     * @author : lijie
-     * @date :2021/10/16 14:35
-     * Update By lijie 2021/10/16 14:35
-     */
-    boolean isBucketExist(String bucketName);
-
-    /***
-     * Description:  创建存储桶
-     * @param bucketName : 存储桶名称
-     * @return : true/false
-     * @author : lijie
-     * @date :2021/10/16 14:35
-     * Update By lijie 2021/10/16 14:35
-     */
-    boolean createBucket(String bucketName);
-
-    /***
-     * Description: 获取访问对象的外链地址
-     * @param bucketName : 存储桶名称
-     * @param objectName : 对象名称
-     * @param expiry : 过期时间(分钟) 最大为7天 超过7天则默认最大值
-     * @return : viewUrl
-     * @author : lijie
-     * @date :2021/10/16 14:41
-     * Update By lijie 2021/10/16 14:41
-     */
-    String getObjectUrl(String bucketName, String objectName, Integer expiry);
-
-    /***
-     * Description: 创建上传文件对象的外链
-     * @param bucketName : 存储桶名称
-     * @param objectName : 欲上传文件对象的名称
-     * @param expiry : 过期时间(分钟) 最大为7天 超过7天则默认最大值
-     * @return : uploadUrl
-     * @author : lijie
-     * @date :2021/10/16 14:41
-     * Update By lijie 2021/10/16 14:41
-     */
-    String createUploadUrl(String bucketName, String objectName, Integer expiry);
-
-    /***
-     * Description: 创建上传文件对象的外链
-     * @param bucketName : 存储桶名称
-     * @param objectName : 欲上传文件对象的名称
-     * @return : java.lang.String
-     * @author : lijie
-     * @date :2021/10/16 14:42
-     * Update By lijie 2021/10/16 14:42
-     */
-    String createUploadUrl(String bucketName, String objectName);
-    /***
-     * Description: 批量创建分片上传外链
-     * @param bucketName : 存储桶名称
-     * @param objectMD5 : 欲上传分片文件主文件的MD5
-     * @param chunkCount : 分片数量
-     * @return : uploadChunkUrls
-     * @author : lijie
-     * @date :2021/10/16 14:43
-     * Update By lijie 2021/10/16 14:43
-     */
-    List<String> createUploadChunkUrlList(String bucketName, String objectMD5, Integer chunkCount);
-
-    /***
-     * Description: 创建指定序号的分片文件上传外链
-     * @param bucketName : 存储桶名称
-     * @param objectMD5 : 欲上传分片文件主文件的MD5
-     * @param partNumber : 分片序号
-     * @return : uploadChunkUrl
-     * @author : lijie
-     * @date :2021/10/16 14:44
-     * Update By lijie 2021/10/16 14:44
-     */
-    String createUploadChunkUrl(String bucketName, String objectMD5, Integer partNumber);
-
-    /***
-     * Description: 获取对象文件名称列表
-     * @param bucketName : 存储桶名称
-     * @param prefix : 对象名称前缀
-     * @param sort : 是否排序(升序)
-     * @return : objectNames
-     * @author : lijie
-     * @date :2021/10/16 14:45
-     * Update By lijie 2021/10/16 14:45
-     */
-    List<String> listObjectNames(String bucketName, String prefix, Boolean sort);
-
-    /***
-     * Description: 获取对象文件名称列表
-     * @param bucketName : 存储桶名称
-     * @param prefix : 对象名称前缀
-     * @return : objectNames
-     * @author : lijie
-     * @date :2021/10/16 14:47
-     * Update By lijie 2021/10/16 14:47
-     */
-    List<String> listObjectNames(String bucketName, String prefix);
-
-    /***
-     * Description: 获取分片文件名称列表
-     * @param bucketName : 存储桶名称
-     * @param ObjectMd5 : 对象Md5
-     * @return : objectChunkNames
-     * @author : lijie
-     * @date :2021/10/16 14:48
-     * Update By lijie 2021/10/16 14:48
-     */
-    List<String> listChunkObjectNames(String bucketName, String ObjectMd5);
-
-    /***
-     * Description: 获取分片名称地址HashMap key=分片序号 value=分片文件地址
-     * @param bucketName : 存储桶名称
-     * @param ObjectMd5 : 对象Md5
-     * @return : objectChunkNameMap
-     * @author : lijie
-     * @date :2021/10/16 14:49
-     * Update By lijie 2021/10/16 14:49
-     */
-    Map<Integer, String> mapChunkObjectNames(String bucketName, String ObjectMd5);
-
-    /***
-     * Description: 合并分片文件成对象文件
-     * @param chunkBucKetName : 分片文件所在存储桶名称
-     * @param composeBucketName : 合并后的对象文件存储的存储桶名称
-     * @param chunkNames : 分片文件名称集合
-     * @param objectName : 合并后的对象文件名称
-     * @return : boolean
-     * @author : lijie
-     * @date :2021/10/16 14:50
-     * Update By lijie 2021/10/16 14:50
-     */
-    boolean composeObject(String chunkBucKetName, String composeBucketName, List<String> chunkNames, String objectName);
-
-    /***
-     * Description: 合并分片文件成对象文件
-     * @param bucketName : 存储桶名称
-     * @param chunkNames : 分片文件名称集合
-     * @param objectName : 合并后的对象文件名称
-     * @return : true/false
-     * @author : lijie
-     * @date :2021/10/16 14:51
-     * Update By lijie 2021/10/16 14:51
-     */
-    boolean composeObject(String bucketName, List<String> chunkNames, String objectName);
-    /***
-     * Description: 获取chuck的bucketName
-     * @param bucketName : 传入的bucketName
-     * @return : java.lang.String
-     * @author : lijie
-     * @date :2021/10/21 10:39
-     * Update By lijie 2021/10/21 10:39
-     */
-    String getChuckBucketName(String bucketName);
-}

+ 78 - 0
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/impl/HdfsStorageServiceImpl.java

@@ -14,6 +14,8 @@ import org.apache.hadoop.fs.Path;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
 
 /**
  * MinIO存储服务实现类
@@ -182,4 +184,80 @@ public class HdfsStorageServiceImpl implements IFileStorageService {
         hashInt = 1000000 + hashInt % HASH_FILE_FOLDER_NUM;
         return ("" + hashInt).substring(3);
     }
+
+    @Override
+    public boolean isBucketExist(String bucketName) {
+        return false;
+    }
+
+    @Override
+    public boolean createBucket(String bucketName) {
+        return false;
+    }
+
+    @Override
+    public String getObjectUrl(String bucketName, String objectName, Integer expiry) {
+        return null;
+    }
+
+    @Override
+    public String createUploadUrl(String bucketName, String objectName, Integer expiry) {
+        return null;
+    }
+
+    @Override
+    public String createUploadUrl(String bucketName, String objectName) {
+        return null;
+    }
+
+    @Override
+    public List<String> createUploadChunkUrlList(String bucketName, String objectMD5, Integer chunkCount) {
+        return null;
+    }
+
+    @Override
+    public String createUploadChunkUrl(String bucketName, String objectMD5, Integer partNumber) {
+        return null;
+    }
+
+    @Override
+    public List<String> listObjectNames(String bucketName, String prefix, Boolean sort) {
+        return null;
+    }
+
+    @Override
+    public List<String> listObjectNames(String bucketName, String prefix) {
+        return null;
+    }
+
+    @Override
+    public List<String> listChunkObjectNames(String bucketName, String ObjectMd5) {
+        return null;
+    }
+
+    @Override
+    public Map<Integer, String> mapChunkObjectNames(String bucketName, String ObjectMd5) {
+        return null;
+    }
+
+    @Override
+    public boolean composeObject(String chunkBucKetName, String composeBucketName,
+                                 List<String> chunkNames, String objectName) {
+        return false;
+    }
+
+    @Override
+    public boolean composeObject(String bucketName, List<String> chunkNames, String objectName) {
+        return false;
+    }
+
+    @Override
+    public String getChuckBucketName(String bucketName) {
+        return null;
+    }
+
+    @Override
+    public Long getObjectSize(String bucketName, String objectName) {
+        return 0L;
+    }
 }

+ 0 - 357
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/impl/MinioCommonServiceImpl.java

@@ -1,357 +0,0 @@
-package com.persagy.dmp.storage.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.StrUtil;
-import com.persagy.dmp.storage.service.MinioCommonService;
-import io.minio.*;
-import io.minio.http.Method;
-import io.minio.messages.Item;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Value;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-@Slf4j
-@RequiredArgsConstructor
-public class MinioCommonServiceImpl implements MinioCommonService, InitializingBean {
-
-    private final MinioClient minioClient;
-
-    @Value("${persagy.common.file.minio.bucket.chunk:persagy-bdtp-chuck}")
-    private String chunkBucKet;
-
-    /**排序*/
-    public final static boolean SORT = true;
-    /**不排序*/
-    public final static boolean NOT_SORT = false;
-    /**默认过期时间(分钟)*/
-    private final static Integer DEFAULT_EXPIRY = 60;
-
-    @Override
-    public void afterPropertiesSet() throws Exception {
-        //方便管理分片文件,则单独创建一个分片文件的存储桶
-        if (!isBucketExist(chunkBucKet)){
-            createBucket(chunkBucKet);
-        }
-    }
-
-    /***
-     * Description: 存储桶是否存在
-     * @param bucketName: 存储桶名称
-     * @return true/false
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:35
-     */
-    @Override
-    @SneakyThrows
-    public boolean isBucketExist(String bucketName){
-        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
-    }
-
-    /***
-     * Description:  创建存储桶
-     * @param bucketName : 存储桶名称
-     * @return : true/false
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:35
-     */
-    @Override
-    @SneakyThrows
-    public boolean createBucket(String bucketName){
-        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
-        return true;
-    }
-
-    /***
-     * Description: 获取访问对象的外链地址
-     * @param bucketName : 存储桶名称
-     * @param objectName : 对象名称
-     * @param expiry : 过期时间(分钟) 最大为7天 超过7天则默认最大值
-     * @return : viewUrl
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:41
-     */
-    @Override
-    @SneakyThrows
-    public String getObjectUrl(String bucketName, String objectName, Integer expiry){
-        expiry = expiryHandle(expiry);
-        return minioClient.getPresignedObjectUrl(
-                GetPresignedObjectUrlArgs.builder()
-                        .method(Method.GET)
-                        .bucket(bucketName)
-                        .object(objectName)
-                        .expiry(expiry)
-                        .build()
-        );
-    }
-
-    /***
-     * Description: 创建上传文件对象的外链
-     * @param bucketName : 存储桶名称
-     * @param objectName : 欲上传文件对象的名称
-     * @param expiry : 过期时间(分钟) 最大为7天 超过7天则默认最大值
-     * @return : uploadUrl
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:41
-     */
-    @Override
-    @SneakyThrows
-    public String createUploadUrl(String bucketName, String objectName, Integer expiry){
-        expiry = expiryHandle(expiry);
-        return minioClient.getPresignedObjectUrl(
-                GetPresignedObjectUrlArgs.builder()
-                        .method(Method.PUT)
-                        .bucket(bucketName)
-                        .object(objectName)
-                        .expiry(expiry)
-                        .build()
-        );
-    }
-
-    /***
-     * Description: 创建上传文件对象的外链
-     * @param bucketName : 存储桶名称
-     * @param objectName : 欲上传文件对象的名称
-     * @return : java.lang.String
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:42
-     */
-    @Override
-    public String createUploadUrl(String bucketName, String objectName){
-        return createUploadUrl(bucketName,objectName,DEFAULT_EXPIRY);
-    }
-
-    /***
-     * Description: 批量创建分片上传外链
-     * @param bucketName : 存储桶名称
-     * @param objectMD5 : 欲上传分片文件主文件的MD5
-     * @param chunkCount : 分片数量
-     * @return : uploadChunkUrls
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:43
-     */
-    @Override
-    public List<String> createUploadChunkUrlList(String bucketName, String objectMD5, Integer chunkCount){
-        if (StrUtil.isBlank(bucketName)){
-            bucketName = chunkBucKet;
-        }
-        if (StrUtil.isBlank(objectMD5)){
-            return null;
-        }
-        objectMD5 += "/";
-        if(null == chunkCount || 0 == chunkCount){
-            return null;
-        }
-        List<String> urlList = new ArrayList<>(chunkCount);
-        for (int i = 1; i <= chunkCount; i++){
-            String objectName = objectMD5 + i + ".chunk";
-            urlList.add(createUploadUrl(bucketName,objectName,DEFAULT_EXPIRY));
-        }
-        return urlList;
-    }
-
-    /***
-     * Description: 创建指定序号的分片文件上传外链
-     * @param bucketName : 存储桶名称
-     * @param objectMD5 : 欲上传分片文件主文件的MD5
-     * @param partNumber : 分片序号
-     * @return : uploadChunkUrl
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:44
-     */
-    @Override
-    public String createUploadChunkUrl(String bucketName, String objectMD5, Integer partNumber){
-        if (StrUtil.isBlank(bucketName)){
-            bucketName = chunkBucKet;
-        }
-        if (StrUtil.isBlank(objectMD5)){
-            return null;
-        }
-        objectMD5 += "/" + partNumber + ".chunk";
-        return createUploadUrl(bucketName,objectMD5,DEFAULT_EXPIRY);
-    }
-
-    /***
-     * Description: 获取对象文件名称列表
-     * @param bucketName : 存储桶名称
-     * @param prefix : 对象名称前缀
-     * @param sort : 是否排序(升序)
-     * @return : objectNames
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:45
-     */
-    @Override
-    @SneakyThrows
-    public List<String> listObjectNames(String bucketName, String prefix, Boolean sort){
-        ListObjectsArgs listObjectsArgs;
-        if(StrUtil.isBlank(prefix)){
-            listObjectsArgs = ListObjectsArgs.builder()
-                    .bucket(bucketName)
-                    .recursive(true)
-                    .build();
-        }else {
-            listObjectsArgs = ListObjectsArgs.builder()
-                    .bucket(bucketName)
-                    .prefix(prefix)
-                    .recursive(true)
-                    .build();
-        }
-        Iterable<Result<Item>> chunks = minioClient.listObjects(listObjectsArgs);
-        List<String> chunkPaths = new ArrayList<>();
-        for (Result<Item> item : chunks){
-            chunkPaths.add(item.get().objectName());
-        }
-        if (sort){
-            return chunkPaths.stream().distinct().collect(Collectors.toList());
-        }
-        return chunkPaths;
-    }
-
-    /***
-     * Description: 获取对象文件名称列表
-     * @param bucketName : 存储桶名称
-     * @param prefix : 对象名称前缀
-     * @return : objectNames
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:47
-     */
-    @Override
-    public List<String> listObjectNames(String bucketName, String prefix){
-        return listObjectNames(bucketName, prefix, NOT_SORT);
-    }
-
-    /***
-     * Description: 获取分片文件名称列表
-     * @param bucketName : 存储桶名称
-     * @param objectMd5 : 对象Md5
-     * @return : objectChunkNames
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:48
-     */
-    @Override
-    public List<String> listChunkObjectNames(String bucketName, String objectMd5){
-        if (StrUtil.isBlank(bucketName)){
-            bucketName = chunkBucKet;
-        }
-        if (StrUtil.isBlank(objectMd5)){
-            return null;
-        }
-        return listObjectNames(bucketName,objectMd5,SORT);
-    }
-
-    /***
-     * Description: 获取分片名称地址HashMap key=分片序号 value=分片文件地址
-     * @param bucketName : 存储桶名称
-     * @param objectMd5 : 对象Md5
-     * @return : objectChunkNameMap
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:49
-     */
-    @Override
-    public Map<Integer, String> mapChunkObjectNames(String bucketName, String objectMd5){
-        if (StrUtil.isBlank(bucketName)){
-            bucketName = chunkBucKet;
-        }
-        if (StrUtil.isBlank(objectMd5)){
-            return new HashMap<>();
-        }
-        List<String> chunkPaths = listObjectNames(bucketName,objectMd5);
-        if (CollUtil.isEmpty(chunkPaths)){
-            return new HashMap<>();
-        }
-        Map<Integer, String> chunkMap = new HashMap<>(chunkPaths.size());
-        for (String chunkName : chunkPaths) {
-            Integer partNumber = Integer.parseInt(chunkName.substring(chunkName.indexOf("/") + 1,chunkName.lastIndexOf(".")));
-            chunkMap.put(partNumber,chunkName);
-        }
-        return chunkMap;
-    }
-
-    /***
-     * Description: 合并分片文件成对象文件
-     * @param chunkBucKetName : 分片文件所在存储桶名称
-     * @param composeBucketName : 合并后的对象文件存储的存储桶名称
-     * @param chunkNames : 分片文件名称集合
-     * @param objectName : 合并后的对象文件名称
-     * @return : boolean
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:50
-     */
-    @Override
-    @SneakyThrows
-    public boolean composeObject(String chunkBucKetName, String composeBucketName, List<String> chunkNames, String objectName){
-        if (StrUtil.isBlank(chunkBucKetName)){
-            chunkBucKetName = chunkBucKet;
-        }
-        List<ComposeSource> sourceObjectList = new ArrayList<>(chunkNames.size());
-        for (String chunk : chunkNames){
-            sourceObjectList.add(
-                    ComposeSource.builder()
-                            .bucket(chunkBucKetName)
-                            .object(chunk)
-                            .build()
-            );
-        }
-        minioClient.composeObject(
-                ComposeObjectArgs.builder()
-                        .bucket(composeBucketName)
-                        .object(objectName)
-                        .sources(sourceObjectList)
-                        .build()
-        );
-        return true;
-    }
-
-    /***
-     * Description: 合并分片文件成对象文件
-     * @param bucketName : 存储桶名称
-     * @param chunkNames : 分片文件名称集合
-     * @param objectName : 合并后的对象文件名称
-     * @return : true/false
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:51
-     */
-    @Override
-    public boolean composeObject(String bucketName, List<String> chunkNames, String objectName){
-        return composeObject(chunkBucKet,bucketName,chunkNames,objectName);
-    }
-
-    /***
-     * Description: 将分钟数转换为秒数
-     * @param expiry : 过期时间(分钟数)
-     * @return : int
-     * @author : lijie
-     * Update By lijie 2021/10/16 14:51
-     */
-    private static int expiryHandle(Integer expiry){
-        expiry = expiry * 60;
-        if (expiry > 604800){
-            return 604800;
-        }
-        return expiry;
-    }
-    /***
-     * Description: 获取chuck的bucketName
-     * @param bucketName : 传入的bucketName
-     * @return : java.lang.String
-     * @author : lijie
-     * @date :2021/10/21 10:39
-     * Update By lijie 2021/10/21 10:39
-     */
-    @Override
-    public String getChuckBucketName(String bucketName){
-        if (StrUtil.isNotBlank(bucketName)){
-            return bucketName;
-        }
-        return chunkBucKet;
-    }
-
-
-}

+ 364 - 6
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/impl/MinioStorageServiceImpl.java

@@ -1,14 +1,25 @@
 package com.persagy.dmp.storage.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.persagy.dmp.common.exception.BusinessException;
+import com.persagy.dmp.file.model.FileMd5;
 import com.persagy.dmp.storage.constant.FileCommonConst;
 import com.persagy.dmp.storage.service.IFileStorageService;
 import io.minio.*;
+import io.minio.http.Method;
+import io.minio.messages.Item;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Value;
 
+import javax.swing.filechooser.FileView;
 import java.io.InputStream;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * MinIO存储服务实现类
@@ -17,10 +28,28 @@ import java.io.InputStream;
  */
 @Slf4j
 @RequiredArgsConstructor
-public class MinioStorageServiceImpl implements IFileStorageService {
+public class MinioStorageServiceImpl implements IFileStorageService, InitializingBean {
 
     private final MinioClient minioClient;
 
+    @Value("${persagy.common.file.minio.bucket.chunk:persagy-bdtp-chuck}")
+    private String chunkBucKet;
+
+    /**排序*/
+    public final static boolean SORT = true;
+    /**不排序*/
+    public final static boolean NOT_SORT = false;
+    /**默认过期时间(分钟)*/
+    private final static Integer DEFAULT_EXPIRY = 60;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        //方便管理分片文件,则单独创建一个分片文件的存储桶
+        if (!isBucketExist(chunkBucKet)){
+            createBucket(chunkBucKet);
+        }
+    }
+
     @Override
     public void upload(String bucketName, String fileName, InputStream input) {
         // 容错判断
@@ -143,15 +172,344 @@ public class MinioStorageServiceImpl implements IFileStorageService {
             bucketName = FileCommonConst.DEFAULT_BUCKET;
         }
         log.info("开始检查桶名:[{0}]是否存在", bucketName);
-//        boolean isExist = minioClient.bucketExists(bucketName);
-        boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
-        if(isExist) {
+        if(isBucketExist(bucketName)) {
             log.info("桶名:[{0}]已存在", bucketName);
             return bucketName;
         }
-//        minioClient.makeBucket(bucketName);
-        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
+        createBucket(bucketName);
         log.info("桶名:[{0}]不存在,创建成功", bucketName);
         return bucketName;
     }
+
+    /***
+     * Description: 存储桶是否存在
+     * @param bucketName: 存储桶名称
+     * @return true/false
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:35
+     */
+    @Override
+    @SneakyThrows
+    public boolean isBucketExist(String bucketName){
+        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
+    }
+
+    /***
+     * Description:  创建存储桶
+     * @param bucketName : 存储桶名称
+     * @return : true/false
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:35
+     */
+    @Override
+    @SneakyThrows
+    public boolean createBucket(String bucketName){
+        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
+        return true;
+    }
+
+    /***
+     * Description: 获取访问对象的外链地址
+     * @param bucketName : 存储桶名称
+     * @param objectName : 对象名称
+     * @param expiry : 过期时间(分钟) 最大为7天 超过7天则默认最大值
+     * @return : viewUrl
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:41
+     */
+    @Override
+    @SneakyThrows
+    public String getObjectUrl(String bucketName, String objectName, Integer expiry){
+        expiry = expiryHandle(expiry);
+        return minioClient.getPresignedObjectUrl(
+                GetPresignedObjectUrlArgs.builder()
+                        .method(Method.GET)
+                        .bucket(bucketName)
+                        .object(objectName)
+                        .expiry(expiry)
+                        .build()
+        );
+    }
+
+    /***
+     * Description: 创建上传文件对象的外链
+     * @param bucketName : 存储桶名称
+     * @param objectName : 欲上传文件对象的名称
+     * @param expiry : 过期时间(分钟) 最大为7天 超过7天则默认最大值
+     * @return : uploadUrl
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:41
+     */
+    @Override
+    @SneakyThrows
+    public String createUploadUrl(String bucketName, String objectName, Integer expiry){
+        expiry = expiryHandle(expiry);
+        return minioClient.getPresignedObjectUrl(
+                GetPresignedObjectUrlArgs.builder()
+                        .method(Method.PUT)
+                        .bucket(bucketName)
+                        .object(objectName)
+                        .expiry(expiry)
+                        .build()
+        );
+    }
+
+    /***
+     * Description: 创建上传文件对象的外链
+     * @param bucketName : 存储桶名称
+     * @param objectName : 欲上传文件对象的名称
+     * @return : java.lang.String
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:42
+     */
+    @Override
+    public String createUploadUrl(String bucketName, String objectName){
+        return createUploadUrl(bucketName,objectName,DEFAULT_EXPIRY);
+    }
+
+    /***
+     * Description: 批量创建分片上传外链
+     * @param bucketName : 存储桶名称
+     * @param objectMD5 : 欲上传分片文件主文件的MD5
+     * @param chunkCount : 分片数量
+     * @return : uploadChunkUrls
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:43
+     */
+    @Override
+    public List<String> createUploadChunkUrlList(String bucketName, String objectMD5, Integer chunkCount){
+        if (StrUtil.isBlank(bucketName)){
+            bucketName = chunkBucKet;
+        }
+        if (StrUtil.isBlank(objectMD5)){
+            return null;
+        }
+        objectMD5 += "/";
+        if(null == chunkCount || 0 == chunkCount){
+            return null;
+        }
+        List<String> urlList = new ArrayList<>(chunkCount);
+        for (int i = 1; i <= chunkCount; i++){
+            String objectName = objectMD5 + i + ".chunk";
+            urlList.add(createUploadUrl(bucketName,objectName,DEFAULT_EXPIRY));
+        }
+        return urlList;
+    }
+
+    /***
+     * Description: 创建指定序号的分片文件上传外链
+     * @param bucketName : 存储桶名称
+     * @param objectMD5 : 欲上传分片文件主文件的MD5
+     * @param partNumber : 分片序号
+     * @return : uploadChunkUrl
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:44
+     */
+    @Override
+    public String createUploadChunkUrl(String bucketName, String objectMD5, Integer partNumber){
+        if (StrUtil.isBlank(bucketName)){
+            bucketName = chunkBucKet;
+        }
+        if (StrUtil.isBlank(objectMD5)){
+            return null;
+        }
+        objectMD5 += "/" + partNumber + ".chunk";
+        return createUploadUrl(bucketName,objectMD5,DEFAULT_EXPIRY);
+    }
+
+    /***
+     * Description: 获取对象文件名称列表
+     * @param bucketName : 存储桶名称
+     * @param prefix : 对象名称前缀
+     * @param sort : 是否排序(升序)
+     * @return : objectNames
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:45
+     */
+    @Override
+    @SneakyThrows
+    public List<String> listObjectNames(String bucketName, String prefix, Boolean sort){
+        ListObjectsArgs listObjectsArgs;
+        if(StrUtil.isBlank(prefix)){
+            listObjectsArgs = ListObjectsArgs.builder()
+                    .bucket(bucketName)
+                    .recursive(true)
+                    .build();
+        }else {
+            listObjectsArgs = ListObjectsArgs.builder()
+                    .bucket(bucketName)
+                    .prefix(prefix)
+                    .recursive(true)
+                    .build();
+        }
+        Iterable<Result<Item>> chunks = minioClient.listObjects(listObjectsArgs);
+        List<String> chunkPaths = new ArrayList<>();
+        for (Result<Item> item : chunks){
+            chunkPaths.add(item.get().objectName());
+        }
+        if (sort){
+            return chunkPaths.stream().distinct().collect(Collectors.toList());
+        }
+        return chunkPaths;
+    }
+
+    /***
+     * Description: 获取对象文件名称列表
+     * @param bucketName : 存储桶名称
+     * @param prefix : 对象名称前缀
+     * @return : objectNames
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:47
+     */
+    @Override
+    public List<String> listObjectNames(String bucketName, String prefix){
+        return listObjectNames(bucketName, prefix, NOT_SORT);
+    }
+
+    /***
+     * Description: 获取分片文件名称列表
+     * @param bucketName : 存储桶名称
+     * @param objectMd5 : 对象Md5
+     * @return : objectChunkNames
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:48
+     */
+    @Override
+    public List<String> listChunkObjectNames(String bucketName, String objectMd5){
+        if (StrUtil.isBlank(bucketName)){
+            bucketName = chunkBucKet;
+        }
+        if (StrUtil.isBlank(objectMd5)){
+            return null;
+        }
+        return listObjectNames(bucketName,objectMd5,SORT);
+    }
+
+    /***
+     * Description: 获取分片名称地址HashMap key=分片序号 value=分片文件地址
+     * @param bucketName : 存储桶名称
+     * @param objectMd5 : 对象Md5
+     * @return : objectChunkNameMap
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:49
+     */
+    @Override
+    public Map<Integer, String> mapChunkObjectNames(String bucketName, String objectMd5){
+        if (StrUtil.isBlank(bucketName)){
+            bucketName = chunkBucKet;
+        }
+        if (StrUtil.isBlank(objectMd5)){
+            return new HashMap<>();
+        }
+        List<String> chunkPaths = listObjectNames(bucketName,objectMd5);
+        if (CollUtil.isEmpty(chunkPaths)){
+            return new HashMap<>();
+        }
+        Map<Integer, String> chunkMap = new HashMap<>(chunkPaths.size());
+        for (String chunkName : chunkPaths) {
+            Integer partNumber = Integer.parseInt(chunkName.substring(chunkName.indexOf("/") + 1,chunkName.lastIndexOf(".")));
+            chunkMap.put(partNumber,chunkName);
+        }
+        return chunkMap;
+    }
+
+    /***
+     * Description: 合并分片文件成对象文件
+     * @param chunkBucKetName : 分片文件所在存储桶名称
+     * @param composeBucketName : 合并后的对象文件存储的存储桶名称
+     * @param chunkNames : 分片文件名称集合
+     * @param objectName : 合并后的对象文件名称
+     * @return : boolean
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:50
+     */
+    @Override
+    @SneakyThrows
+    public boolean composeObject(String chunkBucKetName, String composeBucketName, List<String> chunkNames,
+                                 String objectName){
+        if (StrUtil.isBlank(chunkBucKetName)){
+            chunkBucKetName = chunkBucKet;
+        }
+        List<ComposeSource> sourceObjectList = new ArrayList<>(chunkNames.size());
+        for (String chunk : chunkNames){
+            sourceObjectList.add(
+                    ComposeSource.builder()
+                            .bucket(chunkBucKetName)
+                            .object(chunk)
+                            .build()
+            );
+        }
+        minioClient.composeObject(
+                ComposeObjectArgs.builder()
+                        .bucket(composeBucketName)
+                        .object(objectName)
+                        .sources(sourceObjectList)
+                        .build()
+        );
+        return true;
+    }
+
+    /***
+     * Description: 合并分片文件成对象文件
+     * @param bucketName : 存储桶名称
+     * @param chunkNames : 分片文件名称集合
+     * @param objectName : 合并后的对象文件名称
+     * @return : true/false
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:51
+     */
+    @Override
+    public boolean composeObject(String bucketName, List<String> chunkNames, String objectName){
+        return composeObject(chunkBucKet,bucketName,chunkNames,objectName);
+    }
+
+    /***
+     * Description: 获取chuck的bucketName
+     * @param bucketName : 传入的bucketName
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/10/21 10:39
+     * Update By lijie 2021/10/21 10:39
+     */
+    @Override
+    public String getChuckBucketName(String bucketName){
+        if (StrUtil.isNotBlank(bucketName)){
+            return bucketName;
+        }
+        return chunkBucKet;
+    }
+
+    /***
+     * Description: 获得文件对象的大小
+     * @param bucketName : bucket名称
+     * @param objectName : 对象名称
+     * @return : java.lang.Long
+     * @author : lijie
+     * @date :2021/10/22 18:42
+     * Update By lijie 2021/10/22 18:42
+     */
+    @Override
+    @SneakyThrows
+    public Long getObjectSize(String bucketName, String objectName){
+        StatObjectResponse statObject = minioClient
+                .statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
+        return statObject.size();
+    }
+
+    /***
+     * Description: 将分钟数转换为秒数
+     * @param expiry : 过期时间(分钟数)
+     * @return : int
+     * @author : lijie
+     * Update By lijie 2021/10/16 14:51
+     */
+    private static int expiryHandle(Integer expiry){
+        expiry = expiry * 60;
+        if (expiry > 604800){
+            return 604800;
+        }
+        return expiry;
+    }
+
+
 }

+ 49 - 8
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/utils/FileStorageHelper.java

@@ -1,13 +1,21 @@
 package com.persagy.dmp.storage.utils;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+import com.persagy.dmp.common.constant.ResponseCode;
 import com.persagy.dmp.common.exception.BusinessException;
 import com.persagy.dmp.file.client.FileClientFacade;
+import com.persagy.dmp.file.client.FileMd5ClientFacade;
 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.storage.constant.FileCommonConst;
 import com.persagy.dmp.storage.service.FileStorageFactory;
 import lombok.extern.slf4j.Slf4j;
 
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
+import java.util.List;
 
 /**
  * 文件存储助手
@@ -24,10 +32,32 @@ public class FileStorageHelper {
      * @return
      */
     public static String uploadFile(FileInfo fileInfo, InputStream in) {
+        // 1.获得文件大小
         fileInfo.setFileSize(getStreamSize(in));
-        fileInfo = FileClientFacade.insert(fileInfo);
-        FileStorageFactory.getService().upload(fileInfo.getFileBucket(), fileInfo.getFilePath(), in);
-        return fileInfo.getId();
+        // 2.获得文件的md5值
+        String fileMd5Str = DigestUtil.md5Hex(in);
+        FileMd5 fileMd5 = FileMd5ClientFacade.loadByMd5(fileMd5Str);
+        if (null!=fileMd5
+                && FileCommonConst.UPLOAD_PART.equals(fileMd5.getUploadStatus())){
+            throw new BusinessException(ResponseCode.B0300.getCode(),ResponseCode.B0300.getDesc());
+        }
+        // 3.创建新的存储的fileInfo
+        FileInfo saveFileInfo = FileInfoCreator.of(fileInfo.getGroupCode(), fileInfo.getBusinessId(), fileInfo.getFileName(),
+                fileMd5Str, fileInfo.getExpireDate());
+        // 秒传
+        saveFileInfo = FileClientFacade.insert(saveFileInfo);
+        if (null!=fileMd5
+                && FileCommonConst.UPLOAD_SUCCESS.equals(fileMd5.getUploadStatus())){
+            return saveFileInfo.getId();
+        }
+        // 4.没上传过
+        fileMd5 = FileMd5Creator.of(fileInfo.getFileBucket(), fileMd5Str, FileCommonConst.UPLOAD_SUCCESS);
+        fileMd5.setFileName(fileInfo.getFileName());
+        fileMd5.setGroupCode(fileInfo.getGroupCode());
+        fileMd5.setFileSize(fileInfo.getFileSize());
+        fileMd5 = FileMd5ClientFacade.insert(fileMd5);
+        FileStorageFactory.getService().upload(fileMd5.getFileBucket(), fileMd5.getFilePath(), in);
+        return saveFileInfo.getId();
     }
 
     /**
@@ -80,8 +110,17 @@ public class FileStorageHelper {
      */
     public static void deleteFile(String fileId) {
         FileInfo fileInfo = FileClientFacade.load(fileId);
+        List<FileInfo> fileInfos = FileClientFacade.queryByFileMd5(fileInfo.getFileMd5());
+        if (CollUtil.isNotEmpty(fileInfos) && fileInfos.size()>1){
+            // 多余一个绑定到相同的md5文件上,仅删除文件信息即可
+            FileClientFacade.delete(fileId);
+            return;
+        }
+        // 只有一个绑定到相同的md5文件上,删除文件信息,文件MD5信息,文件信息
+        FileMd5 fileMd5 = FileMd5ClientFacade.loadByMd5(fileInfo.getFileMd5());
         FileClientFacade.delete(fileId);
-        FileStorageFactory.getService().delete(fileInfo.getFileBucket(), fileInfo.getFilePath());
+        FileMd5ClientFacade.delete(fileMd5.getId());
+        FileStorageFactory.getService().delete(fileMd5.getFileBucket(), fileMd5.getFilePath());
     }
 
     /**
@@ -91,7 +130,8 @@ public class FileStorageHelper {
      */
     public static String downloadUrl(String fileId) {
         FileInfo fileInfo = FileClientFacade.load(fileId);
-        return FileStorageFactory.getService().fetchUrl(fileInfo.getFileBucket(), fileInfo.getFilePath());
+        FileMd5 fileMd5 = FileMd5ClientFacade.loadByMd5(fileInfo.getFileMd5());
+        return FileStorageFactory.getService().fetchUrl(fileMd5.getFileBucket(), fileMd5.getFilePath());
     }
 
     /**
@@ -101,7 +141,8 @@ public class FileStorageHelper {
      */
     public static InputStream downloadStream(String fileId) {
         FileInfo fileInfo = FileClientFacade.load(fileId);
-        return FileStorageFactory.getService().download(fileInfo.getFileBucket(), fileInfo.getFilePath());
+        FileMd5 fileMd5 = FileMd5ClientFacade.loadByMd5(fileInfo.getFileMd5());
+        return FileStorageFactory.getService().download(fileMd5.getFileBucket(), fileMd5.getFilePath());
     }
 
     /**