SysFileMultipartServiceImpl.java 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package com.backendsys.modules.upload.service.impl;
  2. import cn.hutool.core.convert.Convert;
  3. import cn.hutool.core.io.file.FileNameUtil;
  4. import cn.hutool.core.util.StrUtil;
  5. import cn.hutool.crypto.digest.DigestUtil;
  6. import com.backendsys.exception.CustException;
  7. import com.backendsys.modules.common.config.security.utils.HttpRequestUtil;
  8. import com.backendsys.modules.sdk.tencentcloud.cos.service.TencentCosService;
  9. import com.backendsys.modules.system.entity.SysCommon;
  10. import com.backendsys.modules.system.service.SysCommonService;
  11. import com.backendsys.modules.upload.dao.SysFileDao;
  12. import com.backendsys.modules.upload.entity.SysFile;
  13. import com.backendsys.modules.upload.service.SysFileMultipartService;
  14. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  15. import com.qcloud.cos.model.*;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.stereotype.Service;
  18. import org.springframework.web.multipart.MultipartFile;
  19. import java.io.IOException;
  20. import java.util.ArrayList;
  21. import java.util.LinkedHashMap;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.concurrent.atomic.AtomicReference;
  25. import java.util.stream.Collectors;
  26. @Service
  27. public class SysFileMultipartServiceImpl implements SysFileMultipartService {
  28. @Autowired
  29. private HttpRequestUtil httpRequestUtil;
  30. @Autowired
  31. private TencentCosService tencentCosService;
  32. @Autowired
  33. private SysFileDao sysFileDao;
  34. @Autowired
  35. private SysCommonService sysCommonService;
  36. /*
  37. 查一下 upload_id 多久会过期
  38. */
  39. // 1.初始化分块上传 (获得 upload_id, object_key)
  40. @Override
  41. public Map<String, Object> multipartUploadInit(MultipartFile multipartFile, Long category_id, Integer upload_chunk_count) {
  42. if (multipartFile.isEmpty()) throw new CustException("file 上传文件不能为空");
  43. if (upload_chunk_count == null) throw new CustException("upload_chunk_count 分块数量不能为空");
  44. // 获得公共配置
  45. List<SysCommon> sysCommonList = sysCommonService.getCommonByCategory("UPLOAD");
  46. AtomicReference<Integer> UPLOAD_TARGET = new AtomicReference<>();
  47. sysCommonList.stream().forEach(sysCommon -> {
  48. if (sysCommon.getTag().equals("UPLOAD_TARGET")) UPLOAD_TARGET.set(Convert.toInt(sysCommon.getValue()));
  49. });
  50. System.out.println("[系统配置] 上传目标(-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云): " + UPLOAD_TARGET);
  51. String target_label = "";
  52. String upload_id = null;
  53. String object_key = null;
  54. // target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
  55. if (UPLOAD_TARGET.get() == 1) {
  56. target_label = "腾讯云初始化分块";
  57. InitiateMultipartUploadResult uploadResult = tencentCosService.initiateMultipartUpload(multipartFile);
  58. upload_id = uploadResult.getUploadId();
  59. object_key = uploadResult.getKey();
  60. }
  61. // 如果没有获得以上参数,则抛出报错
  62. if (StrUtil.isEmpty(upload_id) || StrUtil.isEmpty(object_key)) {
  63. throw new CustException("upload_id 或 object_key 不能为空");
  64. }
  65. // [新增] 上传文件记录
  66. SysFile sysFileEntity = new SysFile();
  67. sysFileEntity.setCategory_id(category_id);
  68. sysFileEntity.setUser_id(httpRequestUtil.getUserId());
  69. sysFileEntity.setUpload_id(upload_id);
  70. sysFileEntity.setUpload_chunk_count(upload_chunk_count);
  71. sysFileEntity.setUpload_chunk_index(0);
  72. sysFileEntity.setName(FileNameUtil.getName(object_key));
  73. sysFileEntity.setObject_key(object_key);
  74. sysFileEntity.setTarget(UPLOAD_TARGET.get());
  75. sysFileEntity.setContent_type(multipartFile.getContentType());
  76. sysFileEntity.setSize(multipartFile.getSize());
  77. sysFileDao.insert(sysFileEntity);
  78. Map<String, Object> resp = new LinkedHashMap<>();
  79. resp.put("target", UPLOAD_TARGET.get());
  80. resp.put("target_label", target_label);
  81. resp.put("upload_chunk_count", upload_chunk_count);
  82. resp.put("upload_id", upload_id);
  83. resp.put("object_key", object_key);
  84. return resp;
  85. }
  86. // 2.上传分块
  87. @Override
  88. public Map<String, Object> multipartUpload(MultipartFile multipartFile, String upload_id, Integer upload_chunk_index) {
  89. if (multipartFile.isEmpty()) throw new CustException("file 上传文件不能为空");
  90. if (StrUtil.isEmpty(upload_id)) throw new CustException("upload_id 不能为空");
  91. if (upload_chunk_index == null) throw new CustException("upload_chunk_index 不能为空");
  92. // [Get] 获得初始化分块信息
  93. SysFile sysFileEntity = sysFileDao.selectOne(new LambdaQueryWrapper<SysFile>().eq(SysFile::getUpload_id, upload_id));
  94. if (sysFileEntity == null) throw new CustException("分块记录不存在");
  95. String object_key = sysFileEntity.getObject_key();
  96. Integer upload_chunk_size = sysFileEntity.getUpload_chunk_count();
  97. if (upload_chunk_index > upload_chunk_size) throw new CustException("分块索引(index)不能大于分块数量(count)");
  98. // 获得公共配置
  99. List<SysCommon> sysCommonList = sysCommonService.getCommonByCategory("UPLOAD");
  100. AtomicReference<Integer> UPLOAD_TARGET = new AtomicReference<>();
  101. sysCommonList.stream().forEach(sysCommon -> {
  102. if (sysCommon.getTag().equals("UPLOAD_TARGET")) UPLOAD_TARGET.set(Convert.toInt(sysCommon.getValue()));
  103. });
  104. System.out.println("[系统配置] 上传目标(-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云): " + UPLOAD_TARGET);
  105. PartETag part_etag = null;
  106. // target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
  107. if (UPLOAD_TARGET.get() == 1) {
  108. UploadPartResult partResult = tencentCosService.uploadPart(multipartFile, upload_id, object_key, upload_chunk_index);
  109. System.out.println("partResult:");
  110. System.out.println(partResult);
  111. part_etag = partResult.getPartETag();
  112. }
  113. // // 查询分块上传情况 (获得下次要上传的位置)
  114. // PartListing partListing = listParts(upload_id, object_key);
  115. // Integer partNumberMarker = partListing.getPartNumberMarker() + 1;
  116. // [Update] 更新分块文件信息
  117. sysFileEntity.setUpload_chunk_index(upload_chunk_index);
  118. sysFileDao.updateById(sysFileEntity);
  119. Map<String, Object> resp = new LinkedHashMap<>();
  120. resp.put("upload_chunk_index", upload_chunk_index);
  121. resp.put("upload_id", upload_id);
  122. resp.put("object_key", object_key);
  123. resp.put("part_etag", part_etag);
  124. return resp;
  125. }
  126. // 完成分块上传
  127. @Override
  128. public Map<String, Object> multipartUploadComplete(String upload_id) {
  129. if (StrUtil.isEmpty(upload_id)) throw new CustException("upload_id 不能为空");
  130. // [Get] 查询文件分块记录
  131. SysFile sysFileEntity = sysFileDao.selectOne(new LambdaQueryWrapper<SysFile>().eq(SysFile::getUpload_id, upload_id));
  132. if (sysFileEntity == null) throw new CustException("upload_id 不存在");
  133. // 判断分块索引和分块数量是否一致
  134. if (sysFileEntity.getUpload_chunk_index() != sysFileEntity.getUpload_chunk_count()) {
  135. throw new CustException("分块索引和分块数量不一致");
  136. }
  137. // 查询分块集合 (etag)
  138. PartListing partListing = listParts(upload_id, sysFileEntity.getObject_key());
  139. List<PartSummary> partSummaryList = partListing.getParts();
  140. List<PartETag> etags = partSummaryList.stream()
  141. .map(partSummary -> new PartETag(partSummary.getPartNumber(), partSummary.getETag()))
  142. .collect(Collectors.toList());
  143. // 如果分块数量对不上,最好还是重新上传
  144. if (sysFileEntity.getUpload_chunk_count() != etags.size()) {
  145. throw new CustException("分块索引异常,请重新上传");
  146. }
  147. // 合并分块
  148. tencentCosService.completeMultipartUpload(upload_id, sysFileEntity.getObject_key(), etags);
  149. return Map.of("upload_id", upload_id);
  150. }
  151. // 查询分块上传情况
  152. @Override
  153. public PartListing listParts(String upload_id, String object_key) {
  154. return tencentCosService.listParts(upload_id, object_key);
  155. }
  156. }