Parcourir la source

fix bug:修复自测文件服务过程中相关功能的bug

lijie il y a 3 ans
Parent
commit
ca8e5eb471
17 fichiers modifiés avec 263 ajouts et 68 suppressions
  1. 27 6
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileController.java
  2. 8 3
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileMd5Controller.java
  3. 30 7
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/TestController.java
  4. 10 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/dao/FileMapper.java
  5. 2 2
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/FileRequestData.java
  6. 1 1
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/domain/UploadMes.java
  7. 9 0
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/IFileService.java
  8. 21 5
      dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileServiceImpl.java
  9. 4 0
      dmp-cloud/dmp-file/src/main/resources/bootstrap.yml
  10. 21 6
      dmp-cloud/dmp-file/src/main/resources/mapper/FileMapper.xml
  11. 7 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileMd5Client.java
  12. 17 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/client/FileMd5ClientFacade.java
  13. 3 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileInfo.java
  14. 15 5
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileInfoCreator.java
  15. 2 0
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/constant/FileCommonConst.java
  16. 1 1
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/service/impl/MinioStorageServiceImpl.java
  17. 85 32
      dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/storage/utils/FileStorageHelper.java

+ 27 - 6
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileController.java

@@ -1,5 +1,6 @@
 package com.persagy.dmp.file.controller;
 
+import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.StrUtil;
 import com.persagy.dmp.common.constant.ResponseCode;
 import com.persagy.dmp.common.constant.ValidEnum;
@@ -11,6 +12,7 @@ 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.FileInfoCreator;
 import com.persagy.dmp.file.service.IFileService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.*;
@@ -32,8 +34,7 @@ public class FileController {
     @PostMapping("/insert")
     public CommonResult<FileInfo> insert(@RequestBody FileInfo fileInfo) {
         if(StrUtil.isBlank(fileInfo.getFileName()) ||
-                StrUtil.isBlank(fileInfo.getGroupCode()) ||
-                StrUtil.isBlank(fileInfo.getFileBucket())) {
+                StrUtil.isBlank(fileInfo.getGroupCode())) {
             throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
         }
         fileInfo.setCreationTime(new PsDateTime());
@@ -46,8 +47,7 @@ public class FileController {
     public CommonResult<FileInfo> update(@RequestBody FileInfo fileInfo) {
         if(StrUtil.isBlank(fileInfo.getId()) ||
                 StrUtil.isBlank(fileInfo.getFileName()) ||
-                StrUtil.isBlank(fileInfo.getGroupCode()) ||
-                StrUtil.isBlank(fileInfo.getFileBucket())) {
+                StrUtil.isBlank(fileInfo.getGroupCode())) {
             throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
         }
         fileInfo.setModifiedTime(new PsDateTime());
@@ -114,7 +114,9 @@ public class FileController {
         // 2.判断必填项
         if(StrUtil.isBlank(requestData.getFileName())
                 || StrUtil.isBlank(requestData.getFileMd5())
-                || StrUtil.isBlank(requestData.getGroupCode())) {
+                || StrUtil.isBlank(requestData.getGroupCode())
+                || null==requestData.getChunkCount()
+                || requestData.getChunkCount()<=0) {
             throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
         }
         return ResultHelper.single(fileService.initChunkUpload(requestData));
@@ -141,6 +143,7 @@ public class FileController {
                 || StrUtil.isBlank(requestData.getFileBucket())) {
             throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
         }
+        FileInfoCreator.checkBucketNameValid(requestData.getFileBucket());
         return ResultHelper.single(fileService.composeFile(requestData));
     }
     /***
@@ -161,12 +164,30 @@ public class FileController {
         if(StrUtil.isBlank(requestData.getFileName())
                 || StrUtil.isBlank(requestData.getFileMd5())
                 || StrUtil.isBlank(requestData.getGroupCode())
-                || StrUtil.isBlank(requestData.getFileBucket())) {
+                || StrUtil.isBlank(requestData.getFileBucket())
+                || null==requestData.getFileSize()) {
             throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
         }
         return ResultHelper.single(fileService.initSingleUpload(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("/initFileDownload")
+    @CrossOrigin(origins = "*",allowCredentials = "true",methods = {RequestMethod.POST,RequestMethod.GET},maxAge = 3600)
+    public CommonResult<FileInfo> initFileDownload(@RequestBody FileRequestData requestData) {
+        //基础参数校验
+        if(StrUtil.isBlank(requestData.getFileId())) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        return ResultHelper.single(fileService.initFileDownload(requestData));
+    }
+    /***
      * Description: 填充一下集团编码
      * @param requestData : 请求参数
      * @return : void

+ 8 - 3
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/FileMd5Controller.java

@@ -84,10 +84,15 @@ public class FileMd5Controller {
         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(fileMd5Service.queryFileMd5ByFileMd5(md5));
+    }
+
+    @PostMapping("/ensureFilePath")
+    public CommonResult<FileMd5> ensureFilePath(@RequestBody FileMd5 fileMd5) {
+        if(null==fileMd5) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
         }
+        fileMd5Service.ensureFilePath(fileMd5,fileMd5.getFileName(),fileMd5.getGroupCode());
         return ResultHelper.single(fileMd5);
     }
 

+ 30 - 7
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/controller/TestController.java

@@ -26,9 +26,6 @@ import java.io.IOException;
 @RequestMapping("/test")
 public class TestController {
 
-    @Autowired
-    IFileService fileService;
-
     @PostMapping(value = "/uploadFile")
     @CrossOrigin
     public CommonResult<FileInfo> uploadFile(@RequestParam("file") MultipartFile multipartFile) throws IOException {
@@ -36,9 +33,35 @@ public class TestController {
         FileInfo fileInfo = FileInfoCreator.of(AppContext.getContext().getGroupCode(),
                 IdWorker.getIdStr(), "ADM", fileName);
         fileInfo.setCreationTime(new PsDateTime());
-        // 可对fileInfo属性额外配置。如有效期等
-        fileService.insertFile(fileInfo);
-        FileStorageFactory.getService().upload(fileInfo.getFileBucket(), fileInfo.getFilePath(), multipartFile.getInputStream());
-        return ResultHelper.single(fileInfo);
+        String fileId = FileStorageHelper.uploadImage(fileInfo, multipartFile.getInputStream());
+        FileInfo dest = new FileInfo();
+        dest.setId(fileId);
+        return ResultHelper.single(dest);
+    }
+    @PostMapping(value = "/replaceFile")
+    @CrossOrigin
+    public CommonResult<FileInfo> replaceFile(@RequestParam("fileId") String fileId,
+                                             @RequestParam("file") MultipartFile multipartFile) throws IOException {
+        String fileName = multipartFile.getResource().getFilename();
+        FileInfo fileInfo = FileInfoCreator.of(AppContext.getContext().getGroupCode(),
+                IdWorker.getIdStr(), "ADM", fileName);
+        fileInfo.setCreationTime(new PsDateTime());
+        FileStorageHelper.replaceFile(fileId,fileName, multipartFile.getInputStream());
+        FileInfo dest = new FileInfo();
+        dest.setId(fileId);
+        return ResultHelper.single(dest);
+    }
+    @PostMapping(value = "/deleteFile")
+    @CrossOrigin
+    public CommonResult<FileInfo> deleteFile(@RequestParam("fileId") String fileId) throws IOException {
+        FileStorageHelper.deleteFile(fileId);
+        FileInfo dest = new FileInfo();
+        dest.setId(fileId);
+        return ResultHelper.single(dest);
+    }
+    @PostMapping(value = "/downloadUrl")
+    @CrossOrigin
+    public CommonResult<FileInfo> downloadUrl(@RequestParam("fileId") String fileId) throws IOException {
+        return ResultHelper.single(FileStorageHelper.downloadUrl(fileId));
     }
 }

+ 10 - 0
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/dao/FileMapper.java

@@ -3,6 +3,7 @@ package com.persagy.dmp.file.dao;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.persagy.dmp.file.model.FileInfo;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * 文件Dao
@@ -11,4 +12,13 @@ import org.apache.ibatis.annotations.Mapper;
  */
 @Mapper
 public interface FileMapper extends BaseMapper<FileInfo> {
+    /***
+     * Description: 根据文件id查询文件信息
+     * @param fileId : 文件id
+     * @return : com.persagy.dmp.file.model.FileInfo
+     * @author : lijie
+     * @date :2021/10/23 13:20
+     * Update By lijie 2021/10/23 13:20
+     */
+    FileInfo getFileInfoById(@Param("fileId") String fileId);
 }

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

@@ -20,8 +20,8 @@ public class FileRequestData implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    /**上传方式,0-直接上传,1-分片上传*/
-    private String uploadFlag;
+    /**文件id*/
+    private String fileId;
 
     /**存储桶名称*/
     private String fileBucket;

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

@@ -11,7 +11,7 @@ import java.util.List;
 @ToString
 public class UploadMes {
     /**文件id*/
-    private String fileId;
+    private String id;
     /**文件上传成功code,200-秒传,201-单个文件上传,202-断点续传且文件分片均已上传,203-断点续传*/
     private Integer uploadCode;
     /**文件上传信息*/

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

@@ -90,4 +90,13 @@ public interface IFileService {
      * Update By lijie 2021/10/22 22:36
      */
     List<FileInfo> queryByFileMd5(String fileMd5);
+    /***
+     * Description: 初始化文件下载
+     * @param requestData : 请求参数
+     * @return : com.persagy.dmp.file.model.FileInfo
+     * @author : lijie
+     * @date :2021/10/23 13:18
+     * Update By lijie 2021/10/23 13:18
+     */
+    FileInfo initFileDownload(FileRequestData requestData);
 }

+ 21 - 5
dmp-cloud/dmp-file/src/main/java/com/persagy/dmp/file/service/impl/FileServiceImpl.java

@@ -1,10 +1,7 @@
 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;
@@ -33,7 +30,6 @@ 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;
 
@@ -48,6 +44,7 @@ import java.util.Map;
 public class FileServiceImpl extends ServiceImpl<FileMapper, FileInfo> implements IFileService {
 
     private final FileMd5Service fileMd5Service;
+    private final FileMapper fileMapper;
 
     @Override
     public FileInfo insertFile(FileInfo vo) {
@@ -229,6 +226,7 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, FileInfo> implement
         this.save(fileInfo);
         fileMd5Service.save(fileMd5);
         UploadMes uploadMes = new UploadMes();
+        uploadMes.setId(fileInfo.getId());
         uploadMes.setUploadCode(UploadCodeEnum.CODE_201.getCode());
         UploadSubMes uploadSubMes = new UploadSubMes();
         uploadSubMes.setPartNumber(0);
@@ -251,6 +249,24 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, FileInfo> implement
         queryWrapper.eq(FileInfo::getValid,true);
         return this.list(queryWrapper);
     }
+    /***
+     * Description: 初始化文件下载
+     * @param requestData : 请求参数
+     * @return : com.persagy.dmp.file.model.FileInfo
+     * @author : lijie
+     * @date :2021/10/23 13:18
+     * Update By lijie 2021/10/23 13:18
+     */
+    @Override
+    public FileInfo initFileDownload(FileRequestData requestData) {
+        FileInfo fileInfo = fileMapper.getFileInfoById(requestData.getFileId());
+        if (null==fileInfo){
+            throw new BusinessException("文件不存在");
+        }
+        String fetchUrl = FileStorageFactory.getService().fetchUrl(fileInfo.getFileBucket(), fileInfo.getFilePath());
+        fileInfo.setFileDownloadUrl(fetchUrl);
+        return fileInfo;
+    }
 
     /***
      * Description: 秒传逻辑
@@ -272,7 +288,7 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, FileInfo> implement
         this.save(fileInfo);
         // 3.组装上传信息
         UploadMes uploadMes = new UploadMes();
-        uploadMes.setFileId(fileInfo.getId());
+        uploadMes.setId(fileInfo.getId());
         uploadMes.setUploadCode(UploadCodeEnum.CODE_200.getCode());
         return uploadMes;
     }

+ 4 - 0
dmp-cloud/dmp-file/src/main/resources/bootstrap.yml

@@ -1,6 +1,10 @@
 spring:
   application:
     name: dmp-file
+  servlet:
+    multipart:
+      max-file-size: 2048MB
+      max-request-size: 2048MB
 #
 #eureka:
 #  client:

+ 21 - 6
dmp-cloud/dmp-file/src/main/resources/mapper/FileMapper.xml

@@ -5,13 +5,8 @@
         <result column="id" property="id"/>
         <result column="group_code" property="groupCode"/>
         <result column="file_name" property="fileName"/>
-        <result column="file_type" property="fileType"/>
-        <result column="file_bucket" property="fileBucket"/>
-        <result column="file_path" property="filePath"/>
-        <result column="file_size" property="fileSize"/>
-        <result column="file_size" property="fileSize"/>
-        <result column="file_size" property="fileSize"/>
         <result column="business_id" property="businessId"/>
+        <result column="file_md5" property="fileMd5"/>
         <result column="expire_date" property="expireDate"/>
         <result column="ts" property="ts"/>
         <result column="creator" property="creator"/>
@@ -19,6 +14,26 @@
         <result column="modifier" property="modifier"/>
         <result column="modified_time" property="modifiedTime"/>
         <result column="valid" property="valid"/>
+        <result column="file_type" property="fileType"/>
+        <result column="file_bucket" property="fileBucket"/>
+        <result column="file_path" property="filePath"/>
+        <result column="file_size" property="fileSize"/>
+        <result column="upload_status" property="uploadStatus"/>
     </resultMap>
+    <select id="getFileInfoById" resultMap="FileMap">
+        SELECT
+            dfi.*,
+            dfm.file_bucket,
+            dfm.file_path,
+            dfm.file_size,
+            dfm.file_type,
+            dfm.upload_status
+        FROM
+            dt_file_info dfi
+                INNER JOIN dt_file_md5 dfm ON ( dfi.file_md5 = dfm.file_md5 )
+        WHERE dfi.id = #{fileId}
+          AND dfi.valid = TRUE
+          AND dfm.valid = TRUE;
+    </select>
 </mapper>
 

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

@@ -54,4 +54,11 @@ public interface FileMd5Client {
      */
     @PostMapping("loadByMd5")
     CommonResult<FileMd5> loadByMd5(@RequestBody String md5);
+    /**
+     * 查询文件MD5信息
+     * @param fileMd5 文件的md5
+     * @return 文件MD5信息
+     */
+    @PostMapping("ensureFilePath")
+    CommonResult<FileMd5> ensureFilePath(@RequestBody FileMd5 fileMd5);
 }

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

@@ -62,4 +62,21 @@ public class FileMd5ClientFacade {
         CommonResult<FileMd5> result = client.loadByMd5(fileMd5);
         return ResultHelper.getContent(result);
     }
+    /**
+     * 查询
+     * @param fileMd5
+     * @return
+     */
+    public static CommonResult<FileMd5> loadByMd5Prototype(String fileMd5) {
+        return client.loadByMd5(fileMd5);
+    }
+    /**
+     * 查询
+     * @param fileMd5:文件MD5信息
+     * @return
+     */
+    public static FileMd5 ensureFilePath(FileMd5 fileMd5) {
+        CommonResult<FileMd5> result = client.ensureFilePath(fileMd5);
+        return ResultHelper.getContent(result);
+    }
 }

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

@@ -42,4 +42,7 @@ public class FileInfo extends AuditableEntity<FileInfo> {
     private String businessId;
     /** 保留期限 */
     private PsDate expireDate;
+    /** 文件下载地址 */
+    @TableField(exist = false)
+    private String fileDownloadUrl;
 }

+ 15 - 5
dmp-comp/dmp-file-starter/src/main/java/com/persagy/dmp/file/model/FileInfoCreator.java

@@ -16,9 +16,6 @@ import java.util.Date;
  */
 public class FileInfoCreator {
 
-    /** 桶名校验正则 */
-    private static final String BUCKET_PATTERN = "^[a-z0-9][a-z0-9\\-]*[a-z0-9]$";
-
     /**
      * 创建FileInfo
      * @param groupCode 集团编码 - 租户
@@ -69,11 +66,24 @@ public class FileInfoCreator {
         // 格式转换
         bucketName = bucketName.toLowerCase();
         // 校验
+        checkBucketNameValid(bucketName);
+        return bucketName;
+    }
+
+    /**
+     * 桶名处理
+     * 将大写转换为小写。
+     * 校验字符:小写字母、连字符、数字,长度为[3,63],开头和结尾必须是字母或数字
+     * https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html
+     * @param bucketName 桶名
+     * @return
+     */
+    public static void checkBucketNameValid(String bucketName) {
+        // 校验
         if(StrUtil.length(bucketName) > 63 ||
-                !ReUtil.isMatch(BUCKET_PATTERN, bucketName)) {
+                !ReUtil.isMatch(FileCommonConst.BUCKET_PATTERN, bucketName)) {
             throw new BusinessException("桶名有误,允许字符:小写字母、连字符、数字,长度为3至63,开头和结尾必须是字母或数字");
         }
-        return bucketName;
     }
 
     /**

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

@@ -16,4 +16,6 @@ public interface FileCommonConst {
 
     /**部分上传*/
     Integer UPLOAD_PART = 1;
+    /** 桶名校验正则 */
+    String BUCKET_PATTERN = "^[a-z0-9][a-z0-9\\-]*[a-z0-9]$";
 }

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

@@ -98,7 +98,7 @@ public class MinioStorageServiceImpl implements IFileStorageService, Initializin
             bucketName = ensureBucket(bucketName);
             // 下载文件
 //            return minioClient.presignedGetObject(bucketName, fileName, FileCommonConst.URL_EXPIRES);
-            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
+            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET)
                     .bucket(bucketName).object(fileName).expiry(FileCommonConst.URL_EXPIRES).build());
         } catch (Exception e) {
             MinioExceptionHandler.handleException(e);

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

@@ -1,6 +1,8 @@
 package com.persagy.dmp.storage.utils;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.NumberUtil;
 import cn.hutool.crypto.digest.DigestUtil;
 import com.persagy.dmp.common.constant.ResponseCode;
 import com.persagy.dmp.common.exception.BusinessException;
@@ -12,7 +14,11 @@ 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 com.sun.corba.se.impl.encoding.WrapperInputStream;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.springframework.util.StreamUtils;
 
 import java.io.*;
 import java.util.List;
@@ -33,32 +39,52 @@ public class FileStorageHelper {
      */
     public static String uploadFile(FileInfo fileInfo, InputStream in) {
         // 1.获得文件大小
-        fileInfo.setFileSize(getStreamSize(in));
+        byte[] streamBytes = getStreamBytes(in);
+        fileInfo.setFileSize((long) streamBytes.length);
         // 2.获得文件的md5值
-        String fileMd5Str = DigestUtil.md5Hex(in);
+        String fileMd5Str = DigestUtil.md5Hex(streamBytes);
         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());
-        // 秒传
+        FileInfo saveFileInfo = FileInfoCreator.of(fileInfo.getGroupCode(),fileInfo.getFileName(),
+                fileInfo.getBusinessId(), fileMd5Str, fileInfo.getExpireDate());
+        // 4.如果文件MD5信息已存在,则直接保存文件信息即可.秒传
         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);
+        if (null!=fileMd5
+                && FileCommonConst.UPLOAD_PART.equals(fileMd5.getUploadStatus())){
+            // 5.文件为断点续传,更改MD5文件信息的文件状态
+            fileMd5.setFileSize(fileInfo.getFileSize());
+            fileMd5.setFileBucket(fileInfo.getFileBucket());
+            fileMd5.setUploadStatus(FileCommonConst.UPLOAD_SUCCESS);
+            fileMd5.setFileName(fileInfo.getFileName());
+            fileMd5.setGroupCode(fileInfo.getGroupCode());
+            fileMd5=FileMd5ClientFacade.ensureFilePath(fileMd5);
+            FileMd5ClientFacade.update(fileMd5);
+        }else {
+            // 6.没上传过,新建MD5文件信息
+            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(), IoUtil.toStream(streamBytes));
         return saveFileInfo.getId();
     }
+    /***
+     * Description: 读取流的字节数组
+     * @param stream : 流
+     * @return : byte[]
+     * @author : lijie
+     * @date :2021/10/23 12:22
+     * Update By lijie 2021/10/23 12:22
+     */
+    private static byte[] getStreamBytes(InputStream stream) {
+        return IoUtil.readBytes(stream);
+    }
 
     /**
      * 上传图片
@@ -81,13 +107,36 @@ public class FileStorageHelper {
      */
     public static String replaceFile(String fileId, String fileName, InputStream in) {
         FileInfo fileInfo = FileClientFacade.load(fileId);
-        // 先删除文件
-        FileStorageFactory.getService().delete(fileInfo.getFileBucket(), fileInfo.getFilePath());
-        // 更新信息后上传
+        byte[] streamBytes = getStreamBytes(in);
+        // 1.判断文件是否已存在,如果已存在则更新文件信息关联的MD5值即可,秒传
+        String fileMd5Str = DigestUtil.md5Hex(streamBytes);
+        FileMd5 newFileMd5 = FileMd5ClientFacade.loadByMd5(fileMd5Str);
+        if (null!=newFileMd5){
+            fileInfo.setFileMd5(fileMd5Str);
+            fileInfo.setFileName(fileName);
+            FileClientFacade.update(fileInfo);
+            return fileInfo.getId();
+        }
+        // 2.判断md5关联的文件信息是否只有当前一个,如果只有一个则删除历史文件
+        List<FileInfo> fileInfos = FileClientFacade.queryByFileMd5(fileInfo.getFileMd5());
+        FileMd5 fileMd5 = FileMd5ClientFacade.loadByMd5(fileInfo.getFileMd5());
+        if (CollUtil.isNotEmpty(fileInfos) && fileInfos.size()==1){
+            // 删除MD5文件信息
+            FileMd5ClientFacade.delete(fileMd5.getId());
+            // 删除文件
+            FileStorageFactory.getService().delete(fileMd5.getFileBucket(), fileMd5.getFilePath());
+        }
+        // 3.更新文件信息,然后重新上传文件
+        FileMd5 uploadFileMd5 = FileMd5Creator.of(fileMd5.getFileBucket(), fileMd5Str, FileCommonConst.UPLOAD_SUCCESS);
+        uploadFileMd5.setFileName(fileName);
+        uploadFileMd5.setGroupCode(fileInfo.getGroupCode());
+        uploadFileMd5.setFileSize((long) streamBytes.length);
+        uploadFileMd5 = FileMd5ClientFacade.insert(uploadFileMd5);
+        fileInfo.setFileMd5(fileMd5Str);
         fileInfo.setFileName(fileName);
-        fileInfo.setFileSize(getStreamSize(in));
-        fileInfo = FileClientFacade.update(fileInfo);
-        FileStorageFactory.getService().upload(fileInfo.getFileBucket(), fileInfo.getFilePath(), in);
+        FileClientFacade.update(fileInfo);
+        FileStorageFactory.getService().upload(uploadFileMd5.getFileBucket(), uploadFileMd5.getFilePath(),
+                IoUtil.toStream(streamBytes));
         return fileInfo.getId();
     }
 
@@ -128,10 +177,14 @@ public class FileStorageHelper {
      * @param fileId 文件id
      * @return 文件下载地址
      */
-    public static String downloadUrl(String fileId) {
+    public static FileInfo downloadUrl(String fileId) {
         FileInfo fileInfo = FileClientFacade.load(fileId);
         FileMd5 fileMd5 = FileMd5ClientFacade.loadByMd5(fileInfo.getFileMd5());
-        return FileStorageFactory.getService().fetchUrl(fileMd5.getFileBucket(), fileMd5.getFilePath());
+        if (null!=fileMd5){
+            String fetchUrl = FileStorageFactory.getService().fetchUrl(fileMd5.getFileBucket(), fileMd5.getFilePath());
+            fileInfo.setFileDownloadUrl(fetchUrl);
+        }
+        return fileInfo;
     }
 
     /**
@@ -160,12 +213,12 @@ public class FileStorageHelper {
      * @param stream
      * @return
      */
-    private static Long getStreamSize(InputStream stream) {
-        try {
-            return Long.valueOf(stream.available());
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-            throw new BusinessException("文件上传失败!");
-        }
-    }
+//    private static Long getStreamSize(InputStream stream) {
+//        try {
+//            return Long.valueOf(stream.available());
+//        } catch (IOException e) {
+//            log.error(e.getMessage(), e);
+//            throw new BusinessException("文件上传失败!");
+//        }
+//    }
 }