Springboot集成华为云obs分段并发上传

1.pom引入华为云配置

    <dependency>
        <groupId>com.huaweicloud</groupId>
        <artifactId>esdk-obs-java-bundle</artifactId>
        <version>3.23.3</version>
    </dependency>

2.application.yml引入华为云配置

#华为云
hwyun:
  obs:
    #OBS存储桶名称
    bucketName:
    #华为云OBS服务节点,如上海(China East)
    endPoint:
    #华为云OBS账户AK
    accessKey:
    #华为云OBS账户SK
    secretKey:

3.添加配置文件HweiOBSConfig

import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * @ClassName: HweiOBSConfig
 * @Description: 华为云OBS配置类
 */
@Data
@Slf4j
@Configuration
public class HweiOBSConfig {
    /**
     * 访问密钥AK
     */
    @Value("${hwyun.obs.accessKey}")
    private String accessKey;

    /**
     * 访问密钥SK
     */
    @Value("${hwyun.obs.secretKey}")
    private String secretKey;

    /**
     * 终端节点
     */
    @Value("${hwyun.obs.endPoint}")
    private String endPoint;

    /**
     * 桶
     */
    @Value("${hwyun.obs.bucketName}")
    private String bucketName;

    /**
     * @return
     * @Description 获取OBS客户端实例
     * @return: com.obs.services.ObsClient
     */
    public ObsClient getInstance() {
        return new ObsClient(accessKey, secretKey, endPoint);
    }


    /**
     * @return
     * @Description 销毁OBS客户端实例
     * @param: obsClient
     */
    public void destroy(ObsClient obsClient) {
        try {
            obsClient.close();
        } catch (ObsException e) {
            log.error("obs执行失败", e);
        } catch (Exception e) {
            log.error("执行失败", e);
        }
    }

    /**
     * @return
     * @Description 微服务文件存放路径
     * @return: java.lang.String
     */
    public static String getObjectKey() {
        // 项目或者服务名称 + 日期存储方式
        return "obs" + "/" + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + "/";
    }

4.新增业务层文件HweiYunOBSService

import com.obs.services.model.CompleteMultipartUploadResult;
import com.obs.services.model.PutObjectResult;
import com.roncoo.education.course.web.model.FileUploadStatus;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.List;

/**
 * @Description 华为云OBS服务接口
 */
public interface HweiYunOBSService {

    /**
     * @Description 删除文件
     * @param: objectKey 文件名
     * @return: boolean 执行结果
     */
    boolean delete(String objectKey);

    /**
     * @Description 批量删除文件
     * @param: objectKeys 文件名集合
     * @return: boolean 执行结果
     */
    boolean delete(List<String> objectKeys);

    /**
     * @Description 上传文件
     * @param: uploadFile 上传文件
     * @param: objectKey 文件名称
     * @return: java.lang.String url访问路径
     */
    PutObjectResult fileUpload(MultipartFile uploadFile, String objectKey);

    /**
     * 并发分片上传
     *
     * @param uploadFile
     * @param objectKey
     * @return
     */
    CompleteMultipartUploadResult splitUpload(MultipartFile uploadFile, String objectKey);

    /**
     * 获取上传速度
     *
     * @param objectKey
     * @return
     */
    public FileUploadStatus getFileUploadPlan(String objectKey);

    /**
     * @Description 文件下载
     */
    InputStream fileDownload(String objectKey);
}

5.业务层实现类文件HweiYunOBSServiceImpl

import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.*;
import com.roncoo.education.course.web.model.FileUploadStatus;
import com.roncoo.education.course.web.model.HweiOBSConfig;
import com.roncoo.education.course.web.service.HweiYunOBSService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: HweiYunOBSServiceImpl
 * @Description: 华为云OBS服务业务层
 */
@Slf4j
@Service
public class HweiYunOBSServiceImpl implements HweiYunOBSService {

    @Autowired
    private HweiOBSConfig hweiOBSConfig;
    // 文件标签
    @Override
    public boolean delete(String objectKey) {
        ObsClient obsClient = null;
        try {
            // 创建ObsClient实例
            obsClient = hweiOBSConfig.getInstance();
            // obs删除
            obsClient.deleteObject(hweiOBSConfig.getBucketName(), objectKey);
        } catch (ObsException e) {
            log.error("obs删除保存失败", e);
        } finally {
            hweiOBSConfig.destroy(obsClient);
        }
        return true;
    }

    @Override
    public boolean delete(List<String> objectKeys) {
        ObsClient obsClient = null;
        try {
            obsClient = hweiOBSConfig.getInstance();
            DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(hweiOBSConfig.getBucketName());
            objectKeys.forEach(deleteObjectsRequest::addKeyAndVersion);
            // 批量删除请求
            obsClient.deleteObjects(deleteObjectsRequest);
            return true;
        } catch (ObsException e) {
            log.error("obs删除保存失败", e);
        } finally {
            hweiOBSConfig.destroy(obsClient);
        }
        return false;
    }

    @Override
    public PutObjectResult fileUpload(MultipartFile uploadFile, String objectKey) {
        ObsClient obsClient = null;
        try {
            String bucketName = hweiOBSConfig.getBucketName();
            // 创建实例
            obsClient = hweiOBSConfig.getInstance();
            // 判断桶是否存在
            boolean exists = obsClient.headBucket(bucketName);
            if (!exists) {
                // 若不存在,则创建桶
                HeaderResponse response = obsClient.createBucket(bucketName);
                log.info("创建桶成功" + response.getRequestId());
            }
            // 获取文件信息
            InputStream inputStream = uploadFile.getInputStream();
            long available = inputStream.available();
            if (available == 0) {
                throw new IllegalArgumentException("No data in the input stream");
            }
            PutObjectRequest request = new PutObjectRequest(bucketName, objectKey, inputStream);
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(available);
            request.setMetadata(objectMetadata);
            // 设置对象访问权限为公共读
            request.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
            PutObjectResult result = obsClient.putObject(request);
            // 读取该已上传对象的URL
            log.info("已上传对象的URL" + result.getObjectUrl());
            return result;
        } catch (ObsException e) {
            log.error("obs上传失败", e);
        } catch (IOException e) {
            log.error("上传失败", e);
        } finally {
            hweiOBSConfig.destroy(obsClient);
        }
        return null;
    }

    @Override
    public CompleteMultipartUploadResult splitUpload(MultipartFile uploadFile, String objectKey) {
        // 初始化线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        List<PartEtag> partETags = Collections.synchronizedList(new ArrayList<>());
        ObsClient obsClient = null;
        CompleteMultipartUploadResult completeMultipartUploadResult = null;
        try {
            String bucketName = hweiOBSConfig.getBucketName();
            // 创建实例
            obsClient = hweiOBSConfig.getInstance();
            // 判断桶是否存在
            boolean exists = obsClient.headBucket(bucketName);
            if (!exists) {
                // 若不存在,则创建桶
                HeaderResponse response = obsClient.createBucket(bucketName);
                log.info("创建桶成功" + response.getRequestId());
            }
            File sampleFile = transferToFile(uploadFile);
            // 初始化分段上传任务
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectKey);
            // 设置对象访问权限为公共读
            request.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
            InitiateMultipartUploadResult result = obsClient.initiateMultipartUpload(request);
            String uploadId = result.getUploadId();
            log.info("\t" + "上传uploadId" + uploadId + "\n");
            // 每段上传10MB
            long partSize = 10 * 1024 * 1024L;
            long fileSize = sampleFile.length();
            // 计算需要上传的段数
            long partCount = fileSize % partSize == 0 ? fileSize / partSize : fileSize / partSize + 1;
            // 执行并发上传段
            for (int i = 0; i < partCount; i++) {
                // 分段在文件中的起始位置
                long offset = i * partSize;
                // 分段大小
                long currPartSize = (i + 1 == partCount) ? fileSize - offset : partSize;
                // 分段号
                int partNumber = i + 1;
                ObsClient finalObsClient = obsClient;
                executorService.execute(() -> {
                    UploadPartRequest uploadPartRequest = new UploadPartRequest();
                    uploadPartRequest.setBucketName(bucketName);
                    uploadPartRequest.setObjectKey(objectKey);
                    uploadPartRequest.setUploadId(uploadId);
                    uploadPartRequest.setFile(sampleFile);
                    uploadPartRequest.setPartSize(currPartSize);
                    uploadPartRequest.setOffset(offset);
                    uploadPartRequest.setPartNumber(partNumber);
                    UploadPartResult uploadPartResult;
                    try {
                        uploadPartResult = finalObsClient.uploadPart(uploadPartRequest);
                        log.info("分段#" + partNumber + " 完成\n");
                        partETags.add(new PartEtag(uploadPartResult.getEtag(), uploadPartResult.getPartNumber()));
                    } catch (ObsException e) {
                        e.printStackTrace();
                    }
                });
            }
            // 等待上传完成
            executorService.shutdown();
            try {
                // 等待线程池关闭,最多等待 5 秒
                if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
                    // 如果等待超时,强制关闭线程池
                    executorService.shutdownNow();
                }
            } catch (InterruptedException e) {
                // 如果等待过程中发生异常,强制关闭线程池
                executorService.shutdownNow();
            }
            while (!executorService.isTerminated()) {
                try {
                    executorService.awaitTermination(5, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    // 如果等待过程中发生异常,强制关闭线程池
                    executorService.shutdownNow();
                }
            }
           /* if (partETags.size() != partCount) {
                throw new IllegalStateException("部分分段未完成!");
            } else {
                System.out.println("成功完成部分" + objectKey + "\n");
            }
             //查看最近上传的所有部分
            ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectKey, uploadId);
            ListPartsResult partListing = obsClient.listParts(listPartsRequest);
            for (Multipart part : partListing.getMultipartList()) {
                System.out.println("\t部分#" + part.getPartNumber() + ", ETag=" + part.getEtag());
            }
            //完成部分
            Collections.sort(partETags, Comparator.comparingInt(PartEtag::getPartNumber));*/
            // 合并段
            CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectKey, uploadId, partETags);
            completeMultipartUploadResult = obsClient.completeMultipartUpload(completeMultipartUploadRequest);
        } catch (ObsException e) {
            log.error("obs上传失败", e);
        } finally {
            try {
                if (obsClient != null) {
                    obsClient.close();
                }
            } catch (ObsException | IOException e) {
                log.error("关闭OBS客户端失败", e);
            } finally {
                hweiOBSConfig.destroy(obsClient);
            }
        }
        return completeMultipartUploadResult;
    }

    /**
     * 获取文件上传进度
     *
     * @param objectKey
     * @return
     */
    @Override
    public FileUploadStatus getFileUploadPlan(String objectKey) {
        ObsClient obsClient = null;
        FileUploadStatus fileUploadStatus = new FileUploadStatus();
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
            obsClient = hweiOBSConfig.getInstance();
            if (obsClient == null) {
                throw new RuntimeException("Failed to get OBS client instance");
            }
            GetObjectRequest request = new GetObjectRequest(hweiOBSConfig.getBucketName(), objectKey);
            request.setProgressListener(status -> {
                // 上传的平均速度
                fileUploadStatus.setAvgSpeed(status.getAverageSpeed());
                // 上传的百分比
                fileUploadStatus.setPct(String.valueOf(status.getTransferPercentage()));
            });
            // 每下载1MB数据反馈下载进度
            request.setProgressInterval(1024 * 1024L);
            ObsObject obsObject = obsClient.getObject(request);
            // 读取对象内容
            InputStream input = obsObject.getObjectContent();
            byte[] b = new byte[1024];
            int len;
            try {
                while ((len = input.read(b)) != -1) {
                    // 将每一次的数据写入缓冲区
                    byteArrayOutputStream.write(b, 0, len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return fileUploadStatus;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            hweiOBSConfig.destroy(obsClient);
        }
        return null;
    }


    @Override
    public InputStream fileDownload(String objectKey) {
        ObsClient obsClient = null;
        try {
            String bucketName = hweiOBSConfig.getBucketName();
            obsClient = hweiOBSConfig.getInstance();
            ObsObject obsObject = obsClient.getObject(bucketName, objectKey);
            return obsObject.getObjectContent();
        } catch (ObsException e) {
            log.error("obs文件下载失败", e);
        } finally {
            hweiOBSConfig.destroy(obsClient);
        }
        return null;
    }

    private File transferToFile(MultipartFile multipartFile) {
        // 选择用缓冲区来实现这个转换即使用java 创建的临时文件 使用 MultipartFile.transferto()方法 。
        File file = null;
        try {
            String originalFilename = multipartFile.getOriginalFilename();
            String[] filename = originalFilename.split("\\.");
            file = File.createTempFile(filename[0], filename[1]);
            multipartFile.transferTo(file);
            file.deleteOnExit();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

}

以上全都集成完毕,然后就可以在项目引入进行接口调用了。

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
华为云OBS提供了分段下载的功能,允许用户将大文件分成多个部分进行下载,从而提高下载效率并节省带宽和时间。华为云OBS分段下载的实现方式是通过HTTP协议的Range头信息来实现的。用户可以通过设置Range头信息中的起始位置和结束位置来指定需要下载的文件片段,服务器将只返回指定片段的数据给用户。 具体实现分段下载的方法如下: 1. 首先,你需要使用Java语言编写代码来实现华为云OBS文件的下载功能。你可以使用华为云OBSJava SDK来简化操作。可以参考中的Java华为云OBS文件上传下载工具类来实现下载功能。 2. 使用华为云OBSJava SDK,你可以通过设置GetObjectRequest对象的range属性来指定需要下载的文件片段的范围。例如,你可以设置range为"0-1023"表示只下载文件的前1024个字节,或者设置range为"1024-"表示从第1024个字节开始的所有数据。 3. 通过调用OBSClient的getObject方法并传入GetObjectRequest对象来发送下载请求。服务器将返回指定片段的数据给用户。 需要注意的是,华为云OBS分段下载功能需要服务器端支持,具体支持的范围大小可能会有限制。在使用分段下载功能时,建议参考华为云OBS的官方文档以了解更多详细信息和限制。 总结起来,华为云OBS提供了分段下载的功能,用户可以通过设置HTTP协议的Range头信息来指定需要下载的文件片段,服务器将只返回指定片段的数据给用户。使用Java语言可以通过华为云OBSJava SDK来实现分段下载功能。具体的实现方法可以参考中的Java华为云OBS文件上传下载工具类。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [图片批量上传至服务器/华为云obs 前台采用webuploader.js div+css布局 图片.zip华为云obs浏览器下载](https://blog.csdn.net/m0_54930214/article/details/127985386)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [华为云OBS文件上传下载工具类](https://blog.csdn.net/weixin_45285213/article/details/125596661)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [华为云obs参考代码以及demo](https://download.csdn.net/download/qq_38707432/10548349)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灬涛声依旧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值