Forráskód Böngészése

1.根据旧ADM调整图类型,边类型的初始化数据
2.实现部分断点续传的逻辑

lijie 3 éve
szülő
commit
6b5a46359e

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dmp-business/dmp-rwd/src/main/resources/db/init/data.sql


+ 2 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/FileRequestData.java

@@ -47,5 +47,7 @@ public class FileRequestData implements Serializable {
     /**集团编码*/
     private String groupCode;
 
+    /**业务id*/
+    private String businessId;
 
 }

+ 51 - 4
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileUploadServiceImpl.java

@@ -4,13 +4,18 @@ 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.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;
@@ -19,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /***
  * Description: 文件上传逻辑处理类
@@ -31,6 +37,8 @@ import java.util.List;
 @Slf4j
 public class FileUploadServiceImpl extends ServiceImpl<FileMapper, FileInfo> implements FileUploadService {
 
+   private final MinioCommonService minioCommonService;
+
     /**上传成功*/
     private static final Integer UPLOAD_SUCCESS = 0;
 
@@ -54,12 +62,34 @@ public class FileUploadServiceImpl extends ServiceImpl<FileMapper, FileInfo> imp
         // 1.根据文件md5值查询数据库
         FileInfo fileInfo = queryFileInfosByFileMd5(requestData.getFileMd5());
         // 2.历史已上传且已完成上传
-        if (ObjectUtil.isNotNull(fileInfo) && UPLOAD_SUCCESS.equals(fileInfo.getUploadStatus())){
+        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);
     }
     /***
@@ -71,7 +101,24 @@ public class FileUploadServiceImpl extends ServiceImpl<FileMapper, FileInfo> imp
      * Update By lijie 2021/10/9 20:36
      */
     private List<FileInfo> firstInitChunkUploadInternal(FileRequestData requestData) {
-        return new ArrayList<>();
+        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(requestData.getGroupCode(),requestData.getBusinessId(),
+                requestData.getBucketName(), requestData.getFileName());
+        fileInfo.setUploadStatus(UPLOAD_PART);
+        fileInfo.setFileMd5(requestData.getFileMd5());
+        this.save(fileInfo);
+        return chunkUploadUrls;
     }
 
     /***

+ 20 - 20
dmp-cloud/dmp-file/src/main/resources/db/init/table.sql

@@ -1,20 +1,20 @@
-CREATE TABLE IF NOT EXISTS `file_info` (
-`id` varchar(64) NOT NULL DEFAULT '' COMMENT 'id',
-`group_code` varchar(100) NOT NULL DEFAULT '' COMMENT '集团编码:租户',
-`file_name` varchar(128) NOT NULL DEFAULT '' 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) COMMENT '文件路径含文件名称 - 对应文件存储路径',
-`file_size` int(11) NOT NULL DEFAULT '0' COMMENT '文件大小',
-`file_md5` varchar(64) NOT NULL DEFAULT NULL COMMENT '文件的md5值',
-`upload_status` int(11) NOT NULL DEFAULT '0' COMMENT '文件上传状态,0.上传完成 1.已上传部分',
-`business_id` varchar(32) DEFAULT NULL COMMENT '关联业务Id',
-`expire_date` char(8) DEFAULT NULL COMMENT '保留期限',
-`creator` varchar(32) DEFAULT NULL COMMENT '创建人',
-`creation_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
-`modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
-`modified_time` timestamp NULL DEFAULT NULL COMMENT '最后修改时间',
-`valid` int(11) DEFAULT NULL COMMENT '合法标识',
-`ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
-PRIMARY KEY (`id`)
-) ENGINE = InnoDB CHARSET = utf8mb4 COMMENT '文件信息';
+CREATE TABLE IF NOT EXISTS `dt_file_info`(
+ `id` varchar(64) NOT NULL COMMENT 'id',
+ `group_code` varchar(100) NOT NULL COMMENT '集团编码:租户',
+ `file_name` varchar(128) 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(0) NOT NULL DEFAULT 0 COMMENT '文件大小',
+ `file_md5` varchar(64) NULL DEFAULT NULL COMMENT '文件的md5值',
+ `upload_status` int(0) 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) NULL DEFAULT NULL COMMENT '创建人',
+ `creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
+ `modifier` varchar(32) NULL DEFAULT NULL COMMENT '最后修改人',
+ `modified_time` char(14) NULL DEFAULT NULL COMMENT '最后修改时间',
+ `valid` int(0) NULL DEFAULT NULL COMMENT '合法标识',
+ `ts` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '乐观锁',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '文件信息';

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

@@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
 @Data
 @EqualsAndHashCode(callSuper = true)
 @TableName(value = "dt_file_info", autoResultMap = true)
-public class FileInfo extends AuditableEntity {
+public class FileInfo extends AuditableEntity<FileInfo> {
 
     /** 集团编码:租户 */
     private String groupCode;

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

@@ -1,6 +1,8 @@
 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;
@@ -26,15 +28,24 @@ public class MinioConfig {
     /** 文件服务器secretKey */
     @Value("${persagy.common.file.secretKey}")
     private String secretKey;
+    /** 文件服务器secretKey */
+    @Value("${persagy.common.file.minio.region:GM+8}")
+    private String minioRegion;
 
     @Bean
     @ConditionalOnProperty(value = "persagy.common.file.storage", havingValue = "0")
     public MinioClient minioClient() {
-        return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
+        return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).region(minioRegion).build();
     }
     @Bean
     @ConditionalOnProperty(value = "persagy.common.file.storage", havingValue = "0")
     public IFileStorageService minioStorageServiceImpl() {
         return new MinioStorageServiceImpl(minioClient());
     }
+
+    @Bean
+    @ConditionalOnProperty(value = "persagy.common.file.storage", havingValue = "0")
+    public MinioCommonService minioCommonService() {
+        return new MinioCommonServiceImpl(minioClient());
+    }
 }

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

@@ -0,0 +1,162 @@
+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);
+}

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

@@ -0,0 +1,342 @@
+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;
+    }
+
+
+}