123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- package com.backendsys.modules.upload.service.impl;
- import cn.hutool.core.convert.Convert;
- import cn.hutool.core.io.file.FileNameUtil;
- import cn.hutool.core.util.StrUtil;
- import cn.hutool.crypto.digest.DigestUtil;
- import com.backendsys.exception.CustException;
- import com.backendsys.modules.common.config.security.utils.HttpRequestUtil;
- import com.backendsys.modules.sdk.tencentcloud.cos.service.TencentCosService;
- import com.backendsys.modules.system.entity.SysCommon;
- import com.backendsys.modules.system.service.SysCommonService;
- import com.backendsys.modules.upload.dao.SysFileDao;
- import com.backendsys.modules.upload.entity.SysFile;
- import com.backendsys.modules.upload.service.SysFileMultipartService;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.qcloud.cos.model.*;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.web.multipart.MultipartFile;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.atomic.AtomicReference;
- import java.util.stream.Collectors;
- @Service
- public class SysFileMultipartServiceImpl implements SysFileMultipartService {
- @Autowired
- private HttpRequestUtil httpRequestUtil;
- @Autowired
- private TencentCosService tencentCosService;
- @Autowired
- private SysFileDao sysFileDao;
- @Autowired
- private SysCommonService sysCommonService;
- /*
- 查一下 upload_id 多久会过期
- */
- // 1.初始化分块上传 (获得 upload_id, object_key)
- @Override
- public Map<String, Object> multipartUploadInit(MultipartFile multipartFile, Long category_id, Integer upload_chunk_count) {
- if (multipartFile.isEmpty()) throw new CustException("file 上传文件不能为空");
- if (upload_chunk_count == null) throw new CustException("upload_chunk_count 分块数量不能为空");
- // 获得公共配置
- List<SysCommon> sysCommonList = sysCommonService.getCommonByCategory("UPLOAD");
- AtomicReference<Integer> UPLOAD_TARGET = new AtomicReference<>();
- sysCommonList.stream().forEach(sysCommon -> {
- if (sysCommon.getTag().equals("UPLOAD_TARGET")) UPLOAD_TARGET.set(Convert.toInt(sysCommon.getValue()));
- });
- System.out.println("[系统配置] 上传目标(-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云): " + UPLOAD_TARGET);
- String target_label = "";
- String upload_id = null;
- String object_key = null;
- // target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
- if (UPLOAD_TARGET.get() == 1) {
- target_label = "腾讯云初始化分块";
- InitiateMultipartUploadResult uploadResult = tencentCosService.initiateMultipartUpload(multipartFile);
- upload_id = uploadResult.getUploadId();
- object_key = uploadResult.getKey();
- }
- // 如果没有获得以上参数,则抛出报错
- if (StrUtil.isEmpty(upload_id) || StrUtil.isEmpty(object_key)) {
- throw new CustException("upload_id 或 object_key 不能为空");
- }
- // [新增] 上传文件记录
- SysFile sysFileEntity = new SysFile();
- sysFileEntity.setCategory_id(category_id);
- sysFileEntity.setUser_id(httpRequestUtil.getUserId());
- sysFileEntity.setUpload_id(upload_id);
- sysFileEntity.setUpload_chunk_count(upload_chunk_count);
- sysFileEntity.setUpload_chunk_index(0);
- sysFileEntity.setName(FileNameUtil.getName(object_key));
- sysFileEntity.setObject_key(object_key);
- sysFileEntity.setTarget(UPLOAD_TARGET.get());
- sysFileEntity.setContent_type(multipartFile.getContentType());
- sysFileEntity.setSize(multipartFile.getSize());
- sysFileDao.insert(sysFileEntity);
- Map<String, Object> resp = new LinkedHashMap<>();
- resp.put("target", UPLOAD_TARGET.get());
- resp.put("target_label", target_label);
- resp.put("upload_chunk_count", upload_chunk_count);
- resp.put("upload_id", upload_id);
- resp.put("object_key", object_key);
- return resp;
- }
- // 2.上传分块
- @Override
- public Map<String, Object> multipartUpload(MultipartFile multipartFile, String upload_id, Integer upload_chunk_index) {
- if (multipartFile.isEmpty()) throw new CustException("file 上传文件不能为空");
- if (StrUtil.isEmpty(upload_id)) throw new CustException("upload_id 不能为空");
- if (upload_chunk_index == null) throw new CustException("upload_chunk_index 不能为空");
- // [Get] 获得初始化分块信息
- SysFile sysFileEntity = sysFileDao.selectOne(new LambdaQueryWrapper<SysFile>().eq(SysFile::getUpload_id, upload_id));
- if (sysFileEntity == null) throw new CustException("分块记录不存在");
- String object_key = sysFileEntity.getObject_key();
- Integer upload_chunk_size = sysFileEntity.getUpload_chunk_count();
- if (upload_chunk_index > upload_chunk_size) throw new CustException("分块索引(index)不能大于分块数量(count)");
- // 获得公共配置
- List<SysCommon> sysCommonList = sysCommonService.getCommonByCategory("UPLOAD");
- AtomicReference<Integer> UPLOAD_TARGET = new AtomicReference<>();
- sysCommonList.stream().forEach(sysCommon -> {
- if (sysCommon.getTag().equals("UPLOAD_TARGET")) UPLOAD_TARGET.set(Convert.toInt(sysCommon.getValue()));
- });
- System.out.println("[系统配置] 上传目标(-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云): " + UPLOAD_TARGET);
- PartETag part_etag = null;
- // target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
- if (UPLOAD_TARGET.get() == 1) {
- UploadPartResult partResult = tencentCosService.uploadPart(multipartFile, upload_id, object_key, upload_chunk_index);
- System.out.println("partResult:");
- System.out.println(partResult);
- part_etag = partResult.getPartETag();
- }
- // // 查询分块上传情况 (获得下次要上传的位置)
- // PartListing partListing = listParts(upload_id, object_key);
- // Integer partNumberMarker = partListing.getPartNumberMarker() + 1;
- // [Update] 更新分块文件信息
- sysFileEntity.setUpload_chunk_index(upload_chunk_index);
- sysFileDao.updateById(sysFileEntity);
- Map<String, Object> resp = new LinkedHashMap<>();
- resp.put("upload_chunk_index", upload_chunk_index);
- resp.put("upload_id", upload_id);
- resp.put("object_key", object_key);
- resp.put("part_etag", part_etag);
- return resp;
- }
- // 完成分块上传
- @Override
- public Map<String, Object> multipartUploadComplete(String upload_id) {
- if (StrUtil.isEmpty(upload_id)) throw new CustException("upload_id 不能为空");
- // [Get] 查询文件分块记录
- SysFile sysFileEntity = sysFileDao.selectOne(new LambdaQueryWrapper<SysFile>().eq(SysFile::getUpload_id, upload_id));
- if (sysFileEntity == null) throw new CustException("upload_id 不存在");
- // 判断分块索引和分块数量是否一致
- if (sysFileEntity.getUpload_chunk_index() != sysFileEntity.getUpload_chunk_count()) {
- throw new CustException("分块索引和分块数量不一致");
- }
- // 查询分块集合 (etag)
- PartListing partListing = listParts(upload_id, sysFileEntity.getObject_key());
- List<PartSummary> partSummaryList = partListing.getParts();
- List<PartETag> etags = partSummaryList.stream()
- .map(partSummary -> new PartETag(partSummary.getPartNumber(), partSummary.getETag()))
- .collect(Collectors.toList());
- // 如果分块数量对不上,最好还是重新上传
- if (sysFileEntity.getUpload_chunk_count() != etags.size()) {
- throw new CustException("分块索引异常,请重新上传");
- }
- // 合并分块
- tencentCosService.completeMultipartUpload(upload_id, sysFileEntity.getObject_key(), etags);
- return Map.of("upload_id", upload_id);
- }
- // 查询分块上传情况
- @Override
- public PartListing listParts(String upload_id, String object_key) {
- return tencentCosService.listParts(upload_id, object_key);
- }
- }
|