java实现大文件分片上传到oss

controller

   private static  final String PATH="fileUpload/";
   /**
     * 功能描述: 初始化
     * @date 13:53 2023/7/6
     */
    @PostMapping("/initSharding")
    public AjaxResult testInitControl(@RequestBody ShardingInfoDo param) {
    
    
        ShardingInfoDo result = new ShardingInfoDo();
        String taskId = UUID.randomUUID().toString().replaceAll("-", "");
        String taskKey = PATH + taskId + param.getFileName();
        result.setTaskId(taskId);
        result.setFileName(param.getFileName());
        String ossSlicesId = ossUtils.getUploadId(taskKey);
        result.setOssSlicesId(ossSlicesId);
        result.setMinSliceSize("100k");
        redisService.setCacheObject(ossSlicesId, result);
        return AjaxResult.success(result);
    }

    /**
     * 功能描述: 分片上传
     * @date 17:17 2023/7/6
     */
    @PostMapping("/uploadShardingFile")
    public AjaxResult testControl(ShardingInfoDo param, MultipartFile file) throws Exception {
    
    
        //必须求出redis中的PartETags,在分片合成文件中需要以此为依据,合并文件返回最终地址
        ShardingInfoDo redisParam = redisService.getCacheObject(param.getOssSlicesId());
        if (redisParam != null)
        {
    
    
            param.setPartETags(redisParam.getPartETags());
        }
        param.setSliceNo(param.getSliceNo()+1);
        int sliceNo = param.getSliceNo();
        int fileSlicesNum = param.getFileSlicesNum();
        String ossSlicesId = param.getOssSlicesId();
        InputStream inputStream = file.getInputStream();
        Map<Integer, PartETag> partETags = param.getPartETags();
        //分片上传
        try
        {
    
    
            //每次上传分片之后,OSS的返回结果会包含一个PartETag
            PartETag partETag = ossUtils.partUploadFile(PATH + param.getTaskId() + param.getFileName(), inputStream, ossSlicesId, param.getFileMD5(), param.getSliceNo(), file.getSize());
            partETags.put(param.getSliceNo(), partETag);
            //分片编号等于总片数的时候合并文件,如果符合条件则合并文件,否则继续等待
            if (fileSlicesNum == sliceNo)
            {
    
    
                //合并文件,注意:partETags必须是所有分片的所以必须存入redis,然后取出放入集合
                String url = ossUtils.completePartUploadFile(PATH + param.getTaskId() + param.getFileName(), ossSlicesId, new ArrayList<>(partETags.values()));
                //oss地址返回后存入并清除redis
                param.setFileUrl(url);
                redisService.deleteObject(ossSlicesId);
                return AjaxResult.success(param);
            } else
            {
    
    
                redisService.setCacheObject(param.getOssSlicesId(), param);
            }
        } catch (Exception e)
        {
    
    
            e.printStackTrace();
            throw new Exception("上传异常");
        }
        return AjaxResult.success();
    }

工具类

package com.ruoyi.common.utils;

import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.util.List;

/**
 * @Auther: ZHANG PU
 * @Date: 2023/7/6 13:17
 * @Description:
 */
@Component
public class OssUtils {
    
    
    private static Logger logger = LoggerFactory.getLogger(OssUtils.class);
    @Value("${oss.endpoint}")
    private String endpoint;
    @Value("${oss.accessKeyId}")
    private String accessKeyId;
    @Value("${oss.accessKeySecret}")
    private String accessKeySecret;
    @Value("${oss.bucketName}")
    private String bucketName;

    private OSS ossClient;

    @PostConstruct
    public void init() {
    
    
        ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    /**
     * 分块上传完成获取结果
     */
    public String completePartUploadFile(String fileKey, String uploadId, List<PartETag> partETags) {
    
    
        CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(bucketName, fileKey, uploadId, partETags);
        CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(request);
        String downLoadUrl = getDownloadUrl(fileKey, bucketName);
        return downLoadUrl;
    }

    /**
     * @param fileKey  文件名称
     * @param is       文件流数据
     * @param uploadId oss唯一分片id
     * @param fileMd5  文件的md5值(非必传)
     * @param partNum  第几片
     * @param partSize 总片数
     * @return
     */
    public PartETag partUploadFile(String fileKey, InputStream is, String uploadId, String fileMd5, int partNum, long partSize) {
    
    
        UploadPartRequest uploadPartRequest = new UploadPartRequest();
        uploadPartRequest.setBucketName(bucketName);
        uploadPartRequest.setUploadId(uploadId);
        uploadPartRequest.setPartNumber(partNum);
        uploadPartRequest.setPartSize(partSize);
        uploadPartRequest.setInputStream(is);
        uploadPartRequest.setKey(fileKey);
        uploadPartRequest.setMd5Digest(fileMd5);
        UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
        return uploadPartResult.getPartETag();
    }

    /**
     * 分块上传完成获取结果
     */
    public String getUploadId(String fileKey) {
    
    
        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, fileKey);
        // 初始化分片
        InitiateMultipartUploadResult unrest = ossClient.initiateMultipartUpload(request);
        // 返回uploadId,它是分片上传事件的唯一标识,您可以根据这个ID来发起相关的操作,如取消分片上传、查询分片上传等。
        String uploadId = unrest.getUploadId();
        return uploadId;
    }

    /**
     * 获取bucket文件的下载链接
     *
     * @param pathFile   首字母不带/的路径和文件
     * @param bucketName
     * @return 上报返回null, 成功返回地址
     */
    public String getDownloadUrl(String pathFile, String bucketName) {
    
    
        StringBuffer url = new StringBuffer();
        url.append(endpoint).append("/");
        if (pathFile != null && !"".equals(pathFile))
        {
    
    
            url.append(pathFile);
        }
        return url.toString().replace("https://", "https://" + bucketName + ".");
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_42456784/article/details/131700260