阿里云OSS大文件上传

package com.medicine.management_side.utils;

import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class OSSMultipartUploadUtil {

    private static  String ACCESS_ID = "";
    private static  String ACCESS_KEY = "";
    private static  String OSS_ENDPOINT = "";
    private static  long PART_SIZE = 1 * 1024 * 1024L; // 每个Part的大小,最小为1M
    private static  int CONCURRENCIES = 2; // 上传Part的并发线程数。
    private static  String partUrl = "";

    private static String bucketName = ""; // 需要存储的bucketName
    private static String picLocation = "bigFile/"; // 图片保存路径
    static {
        try {
            Resource resource = new ClassPathResource("/application.properties");
            Properties props = PropertiesLoaderUtils.loadProperties(resource);

            if("0".equals(props.getProperty("isnable").toString())){
                Resource resourceTest = new ClassPathResource("/oss.properties");
                Properties propsTest = PropertiesLoaderUtils.loadProperties(resourceTest);
                OSS_ENDPOINT = propsTest.getProperty("endpoint").toString();
                //System.out.println("ttttttttttttttttt111"+OSS_ENDPOINT);
                ACCESS_ID = propsTest.getProperty("accessKeyId").toString();
                ACCESS_KEY = propsTest.getProperty("accessKeySecret").toString();
                bucketName = propsTest.getProperty("bucketName").toString();

            }else if("1".equals(props.getProperty("isnable").toString())){

                Resource resourceArea = new ClassPathResource("/oss.properties");
                Properties propsArea = PropertiesLoaderUtils.loadProperties(resourceArea);
                OSS_ENDPOINT = propsArea.getProperty("endpointn").toString();//青岛内网
               // System.out.println("222222222222222222222"+OSS_ENDPOINT);
                ACCESS_ID = propsArea.getProperty("accessKeyId").toString();
                ACCESS_KEY = propsArea.getProperty("accessKeySecret").toString();
                bucketName = propsArea.getProperty("bucketName").toString();
            }

        } catch (IOException e) {
            e.printStackTrace();

        }

    }

    /**
     * 分段上传大文件,同时返回 原图和缩略图 通过Multipart的方式上传一个大文件,要上传文件的大小必须大于一个Part允许的最小大小,即5MB。
     * @throws OSSException
     * @throws ClientException
     * @throws InterruptedException
     */
    public static PageData uploadBigFileAndOssUplodeSingdUrl(MultipartFile file,String filename) throws OSSException, ClientException, InterruptedException {
        long begin = System.currentTimeMillis();
        ClientConfiguration config = new ClientConfiguration();
        config.setConnectionTimeout(15 * 1000); // 连接超时,默认15秒
        config.setSocketTimeout(15 * 1000);// socket超时,默认15秒
        config.setMaxConnections(10); // // 设置HTTP最大连接数为10
        config.setMaxErrorRetry(2);// 失败后最大重试次数
        OSSClient client = new OSSClient(OSS_ENDPOINT, ACCESS_ID, ACCESS_KEY, config);
        // OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret,conf);
        //String key = String.format("%s%s.%s",picLocation,UuidUtil.get32UUID(),fileTypeName);
        String key = "patient/"+filename;
        int partCount = calPartCount(file.getSize());
        //  System.out.println("partCountpartCountpartCountpartCount"+partCount);
        if (partCount <= 1) {
            throw new IllegalArgumentException("要上传文件的大小必须大于一个Part的字节数:" + PART_SIZE);
        }
        String uploadId = initMultipartUpload(client,bucketName, key);
        ExecutorService pool = Executors.newFixedThreadPool(CONCURRENCIES);
        List<PartETag> eTags = Collections.synchronizedList(new ArrayList<PartETag>());

        for (int i = 0; i < partCount; i++) {
            long start = PART_SIZE * i;
            long curPartSize = PART_SIZE < file.getSize() - start ? PART_SIZE : file.getSize() - start;
            pool.execute(new UploadPartThread(client,bucketName, key,file, uploadId, i + 1, PART_SIZE * i, curPartSize,eTags));
        }
        pool.shutdown();
        while (!pool.isTerminated()) {
            pool.awaitTermination(5, TimeUnit.SECONDS);
        }
        if (eTags.size() != partCount) {
            throw new IllegalStateException("Multipart上传失败,有Part未上传成功。");
        }
        completeMultipartUpload(client,bucketName, key, uploadId, eTags);
        String fileUrl = "";
        long end = System.currentTimeMillis();
        // System.out.println(end - begin);
        Date expiration = new Date(new Date().getTime() + 3600l*1000*24*365*100);
// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
        fileUrl = client.generatePresignedUrl(bucketName,  key, expiration).toString().replace("-internal", "");


        // 将图片缩放为固定宽高100 px。
        String style = "image/resize,l_100";
        GeneratePresignedUrlRequest req= new GeneratePresignedUrlRequest(bucketName,key);

        req.setExpiration(expiration);
        req.setProcess(style);
        String singdUrl=  client.generatePresignedUrl(req).toString();
           PageData pd=new PageData();
           pd.put("fileUrl",fileUrl);//原图
           pd.put("singdUrl",singdUrl);//缩略图
        return pd;
    }

    /**
     * 分段上传大文件,通过Multipart的方式上传一个大文件,要上传文件的大小必须大于一个Part允许的最小大小,即5MB。
     * @throws OSSException
     * @throws ClientException
     * @throws InterruptedException
     */
    public static String uploadBigFile(MultipartFile file,String filename) throws OSSException, ClientException, InterruptedException {
        long begin = System.currentTimeMillis();
        ClientConfiguration config = new ClientConfiguration();
        config.setConnectionTimeout(15 * 1000); // 连接超时,默认15秒
        config.setSocketTimeout(15 * 1000);// socket超时,默认15秒
        config.setMaxConnections(10); // // 设置HTTP最大连接数为10
        config.setMaxErrorRetry(2);// 失败后最大重试次数
        OSSClient client = new OSSClient(OSS_ENDPOINT, ACCESS_ID, ACCESS_KEY, config);
       // OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret,conf);
        //String key = String.format("%s%s.%s",picLocation,UuidUtil.get32UUID(),fileTypeName);
        String key = "patient/"+filename;
        int partCount = calPartCount(file.getSize());
      //  System.out.println("partCountpartCountpartCountpartCount"+partCount);
        if (partCount <= 1) {
            throw new IllegalArgumentException("要上传文件的大小必须大于一个Part的字节数:" + PART_SIZE);
        }
        String uploadId = initMultipartUpload(client,bucketName, key);
        ExecutorService pool = Executors.newFixedThreadPool(CONCURRENCIES);
        List<PartETag> eTags = Collections.synchronizedList(new ArrayList<PartETag>());

        for (int i = 0; i < partCount; i++) {
            long start = PART_SIZE * i;
            long curPartSize = PART_SIZE < file.getSize() - start ? PART_SIZE : file.getSize() - start;
            pool.execute(new UploadPartThread(client,bucketName, key,file, uploadId, i + 1, PART_SIZE * i, curPartSize,eTags));
        }
        pool.shutdown();
        while (!pool.isTerminated()) {
            pool.awaitTermination(5, TimeUnit.SECONDS);
        }
        if (eTags.size() != partCount) {
            throw new IllegalStateException("Multipart上传失败,有Part未上传成功。");
        }
        completeMultipartUpload(client,bucketName, key, uploadId, eTags);
        String fileUrl = "";
        long end = System.currentTimeMillis();
       // System.out.println(end - begin);
        Date expiration = new Date(new Date().getTime() + 3600l*1000*24*365*100);
// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
        fileUrl = client.generatePresignedUrl(bucketName,  key, expiration).toString().replace("-internal", "");

        return fileUrl;
    }
    /**
     * 分段上传大文件获得缩略图,通过Multipart的方式上传一个大文件,要上传文件的大小必须大于一个Part允许的最小大小,即5MB。
     * @throws OSSException
     * @throws ClientException
     * @throws InterruptedException
     */
    public static String ossUplodeSingdUrl(MultipartFile file,String filename) throws OSSException, ClientException, InterruptedException {
        long begin = System.currentTimeMillis();
        ClientConfiguration config = new ClientConfiguration();
        config.setConnectionTimeout(15 * 1000); // 连接超时,默认15秒
        config.setSocketTimeout(15 * 1000);// socket超时,默认15秒
        config.setMaxConnections(10); // // 设置HTTP最大连接数为10
        config.setMaxErrorRetry(2);// 失败后最大重试次数
        OSSClient client = new OSSClient(OSS_ENDPOINT, ACCESS_ID, ACCESS_KEY, config);
        // OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret,conf);
        //String key = String.format("%s%s.%s",picLocation,UuidUtil.get32UUID(),fileTypeName);
        String key = "patient/"+filename;
        int partCount = calPartCount(file.getSize());
        //  System.out.println("partCountpartCountpartCountpartCount"+partCount);
        if (partCount <= 1) {
            throw new IllegalArgumentException("要上传文件的大小必须大于一个Part的字节数:" + PART_SIZE);
        }
        String uploadId = initMultipartUpload(client,bucketName, key);
        ExecutorService pool = Executors.newFixedThreadPool(CONCURRENCIES);
        List<PartETag> eTags = Collections.synchronizedList(new ArrayList<PartETag>());

        for (int i = 0; i < partCount; i++) {
            long start = PART_SIZE * i;
            long curPartSize = PART_SIZE < file.getSize() - start ? PART_SIZE : file.getSize() - start;
            pool.execute(new UploadPartThread(client,bucketName, key,file, uploadId, i + 1, PART_SIZE * i, curPartSize,eTags));
        }
        pool.shutdown();
        while (!pool.isTerminated()) {
            pool.awaitTermination(5, TimeUnit.SECONDS);
        }
        if (eTags.size() != partCount) {
            throw new IllegalStateException("Multipart上传失败,有Part未上传成功。");
        }
        completeMultipartUpload(client,bucketName, key, uploadId, eTags);
        long end = System.currentTimeMillis();
        // System.out.println(end - begin);
        Date expiration = new Date(new Date().getTime() + 3600l*1000*24*365*100);

        // 将图片缩放为固定宽高100 px。
        String style = "image/resize,l_100";
        GeneratePresignedUrlRequest req= new GeneratePresignedUrlRequest(bucketName,key);

        req.setExpiration(expiration);
        req.setProcess(style);
        String singdUrl=  client.generatePresignedUrl(req).toString();

        return singdUrl;
    }

    // 根据文件的大小和每个Part的大小计算需要划分的Part个数。
    private static int calPartCount(long length) {
        int partCount = (int) (length / PART_SIZE);
        if (length % PART_SIZE != 0) {
            partCount++;
        }
        return partCount;
    }

    // 初始化一个Multi-part upload请求。
    private static String initMultipartUpload(OSSClient client,String bucketName, String key) throws OSSException, ClientException {
        InitiateMultipartUploadRequest initUploadRequest = new InitiateMultipartUploadRequest(bucketName, key);
        InitiateMultipartUploadResult initResult = client.initiateMultipartUpload(initUploadRequest);
        String uploadId = initResult.getUploadId();
        return uploadId;
    }

    // 完成一个multi-part请求。
    private static void completeMultipartUpload(OSSClient client,String bucketName, String key, String uploadId, List<PartETag> eTags) throws OSSException, ClientException {
        // 为part按partnumber排序
        Collections.sort(eTags, new Comparator<PartETag>() {
            public int compare(PartETag arg0, PartETag arg1) {
                PartETag part1 = arg0;
                PartETag part2 = arg1;
                return part1.getPartNumber() - part2.getPartNumber();
            }
        });
        CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, key, uploadId, eTags);
        client.completeMultipartUpload(completeMultipartUploadRequest);
    }

    private static class UploadPartThread implements Runnable {
        private MultipartFile file;
        private String bucket;
        private String object;
        private long start;
        private long size;
        private List<PartETag> eTags;
        private int partId;
        private OSSClient client;
        private String uploadId;

        UploadPartThread(OSSClient client,String bucket, String object,MultipartFile file, String uploadId, int partId, long start,long partSize, List<PartETag> eTags) {
            this.file = file;
            this.bucket = bucket;
            this.object = object;
            this.start = start;
            this.size = partSize;
            this.eTags = eTags;
            this.partId = partId;
            this.client = client;
            this.uploadId = uploadId;
        }

        @Override
        public void run() {
            InputStream in = null;
            try {
                in = file.getInputStream();
                in.skip(start);

                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(bucket);
                uploadPartRequest.setKey(object);
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(in);
                uploadPartRequest.setPartSize(size);
                uploadPartRequest.setPartNumber(partId);

                UploadPartResult uploadPartResult = client.uploadPart(uploadPartRequest);
                eTags.add(uploadPartResult.getPartETag());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null)
                    try {
                        in.close();
                    } catch (Exception e) {
                    }
            }
        }
    }
}
阿里云OSS大文件上传可采用分片上传的方式,以下是相关信息: ### 后端Controller示例 后端可创建一个Controller来处理分片上传请求,示例代码如下: ```java import org.springframework.web.bind.annotation.RestController; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.beans.factory.annotation.Autowired; import java.util.Map; @RestController @Log4j2 @Api(tags = "分片上传") public class UpLoadController { @Autowired private UpLoadService upLoadService; /** * 分片上传 * @param uploadParams * @return Result */ @ApiOperation(value = "分片上传") @PostMapping("/file/uploadFile") public Result<Map<String,Object>> fileUploadZone(UploadParams uploadParams) { return upLoadService.fileUploadZone(uploadParams); } } ``` 该Controller接收`UploadParams`类型的参数,调用`UpLoadService`的`fileUploadZone`方法处理分片上传请求,并返回结果[^3]。 ### 前期准备 在Maven工程中使用OSS Java SDK,需在`pom.xml`中加入以下依赖: ```xml <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.17.4</version> </dependency> ``` 这样才能使用相关的OSS SDK进行文件上传操作[^4]。 ### 工具类创建 可以创建一个OSS文件管理的`OSSManageUtil`工具类。OSS文件存储是对Object的操作,只要写好路径,相关目录会自动创建。`OSSClient`是OSS的核心,可深入研究其使用方法。例如在上传特定类型文件(如上传apk)时,要注意`contentType`的设置,上传apk需使用`application/octet-stream`类型[^2]。 ### 整体思路 使用阿里云OSS对象存储服务进行文件上传业务时,前端上传文件请求到服务端后,无需在服务器本地磁盘存储文件,直接将接收到的文件上传OSS,由OSS负责存储和管理,且阿里云OSS存储服务能保障所存储内容的安全可靠[^1]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值