阿里云oss分片上传示例

oss文件服务器分片上传官方文档参考: 分片上传 - 对象存储 OSS - 阿里云
官方文档写的更加详细,更多内容请参考官方文档

oss分片上传流程

1.初始化分片事件,向oss服务器获取全局唯一的uploadId
  • 获取uploadId,后续分片都需带上uploadId,标识同一个文件对象。
  • 另外初始化操作时已经指定文件访问链接,还可以添加一些请求头,如缓存、文件私有访问控制等条件。*
2.开始切片上传
  • 分片一般由前端完成,通过后端将分片上传到oss服务器,上传时也无需按照顺序上传。
  • 也可由前端直接上传到oss服务器,此时后端仅需要向前端颁发凭证即可。
  • 需要注意的是,在分片上传成功后需保存响应数据,留待第三步使用。*
3.分片上传完成,合并上传
  • 分片上传完成后,需主动通知oss服务器合并文件。*

2.代码示例

开始前准备
依赖导入
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.13.2</version>
</dependency> 
sql
  • 文件上传记录表
CREATE TABLE `file_upload_record` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `filename` varchar(255) DEFAULT NULL COMMENT '文件原名称',
  `md5` varchar(255) DEFAULT NULL COMMENT 'md5',
  `upload_id` varchar(255) DEFAULT NULL COMMENT 'uploadId',
  `paths` varchar(255) DEFAULT NULL COMMENT '图片地址',
  `status` varchar(255) DEFAULT NULL COMMENT '状态:wait/succ',
  `upload_start_time` datetime DEFAULT NULL COMMENT '上传起始时间',
  `upload_end_time` datetime DEFAULT NULL COMMENT '上传结束时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=39 DEFAULT CHARSET=utf8;
  • 分片上传结果记录表
CREATE TABLE `part_upload_record` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `upload_id` varchar(255) DEFAULT NULL COMMENT '唯一上传id',
  `part_number` int(11) DEFAULT NULL COMMENT '当前片数',
  `md5` varchar(255) DEFAULT NULL COMMENT '当前片的md5值',
  `upload_result` varchar(255) DEFAULT NULL COMMENT '分片上传结果(json)',
  `upload_time` datetime DEFAULT NULL COMMENT '分片上传时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=utf8;
请求对象
@Data
@ApiModel("分片上传实体")
public class MultipartUploadDto {
    /**
     * 唯一上传id
     */
    @ApiModelProperty(value = "分片上传id",required = true)
    @NotBlank(message = "上传id不能为空")
    private String uploadId;
    /**
     * 当前片数
     */
    @ApiModelProperty(value = "当前片数",required = true)
    @NotNull(message = "当前片数不能为空")
    private int partNumber;
    /**
     * 当前片大小
     */
    @ApiModelProperty(value = "当前片大小",required = true)
    @NotNull(message = "当前片大小不能为空")
    private long partSize;
    /**
     * 总片数
     */
    @ApiModelProperty(value = "总片数",required = true)
    @NotNull(message = "总片数不能为空")
    private int totalPart;
    /**
     * 当前片的md5值
     */
    @ApiModelProperty(value = "当前片的md5")
    private String md5;
    /**
     * 文件
     */
    @ApiModelProperty(value = "当前片文件",required = true)
    @NotNull(message = "文件不能为空")
    private MultipartFile file;
}
获取uploadId
1.初始化 ossClient
  {
        // 创建OSSClient实例。
        ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

    }
2.获取uploadId
/**
     * 获取文件上传id
     * @param fileName 文件名称
     * @return r
     */
    public UploadIdRespDto getUploadId(String fileName) {
        // 文件名称
        String objectName = "multipart" + "/" + UUID.randomUUID().toString().replaceAll("-", "") + "." + getFileExtName(fileName);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
//        //指定该Object的网页缓存行为。
        metadata.setCacheControl("no-cache");
        //设置文件为私有
        metadata.setObjectAcl(CannedAccessControlList.Private);
//        //指定该Object被下载时的名称。
        metadata.setContentDisposition("attachment;filename=" + fileName);
        // 创建InitiateMultipartUploadRequest对象。
        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
        // 初始化分片。
        InitiateMultipartUploadResult upResult = ossClient.initiateMultipartUpload(request);
        uploadService.addFileUploadRecord(upResult.getUploadId(), objectName, fileName);
        // 返回uploadId,它是分片上传事件的唯一标识。您可以根据该uploadId发起相关的操作,例如取消分片上传、查询分片上传等。
        log.info("获取uploadId成功,结果:{}", upResult);
        return UploadIdRespDto.builder()
                .uploadId(upResult.getUploadId())
                .paths(objectName)
                .prefix("https://" + bucketName + "." + endpoint.substring(8))
                .build();
    }
分片上传
    public MultipartUploadRespDto partUpload(MultipartUploadDto param) {
        String uploadId = param.getUploadId();
        // int total = param.getTotalPart();
        StopWatch st = new StopWatch();
        st.start();
        //封装分片上传请求
        UploadPartRequest uploadPartRequest = new UploadPartRequest();
        uploadPartRequest.setUploadId(param.getUploadId());
        //part大小 1-10000
        uploadPartRequest.setPartNumber(param.getPartNumber());
        uploadPartRequest.setPartSize(param.getPartSize());
        uploadPartRequest.setBucketName(bucketName);
        try {
            uploadPartRequest.setInputStream(param.getFile().getInputStream());
        } catch (IOException e) {
            throw new BusinessException("文件流异常");
        }

        FileUploadRecordEo uploadRecordEo = uploadService.findFileByUploadId(uploadId);
        if (uploadRecordEo == null) {
            throw new BusinessException("上传标识符异常!");
        }
        String objectName = uploadRecordEo.getPaths();
        uploadPartRequest.setKey(objectName);
        //查询该分片是否已上传
        boolean existPartNumber = uploadService.isExistPartNumber(uploadId, uploadPartRequest.getPartNumber());
        if (existPartNumber) {
            return MultipartUploadRespDto.builder().isUpload(1)
                    .partNumber(uploadPartRequest.getPartNumber())
                    .uploadId(uploadPartRequest.getUploadId())
                    .build();
        }
        // 每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会按照分片号排序组成完整的文件。
        UploadPartResult uploadPartResult = null;
        try {
            uploadPartResult = ossClient.uploadPart(uploadPartRequest);
        } catch (OSSException e) {
            e.printStackTrace();
            throw new BusinessException("上传失败:" + e.getMessage());
        } catch (com.aliyun.oss.ClientException e) {
            e.printStackTrace();
            throw new BusinessException("上传失败,客户端错误:" + e.getMessage());
        }
        st.stop();
        log.info("{}文件第 {} 片上传成功,上传结果:{},耗时:{}", uploadId, uploadPartRequest.getPartNumber(), JSON.toJSON(uploadPartResult), st.getTotalTimeMillis());
        //保留分片上传接口
        uploadService.addPartUploadRecord(uploadPartResult.getPartETag(), param);
        //主动合并
//        List<PartETag> partTagList = uploadService.findPartTagListByUploadId(uploadId);
//
//        if (partTagList.size() == total) {
//            //上传成功
//            // 创建CompleteMultipartUploadRequest对象。
//            // 在执行完成分片上传操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每个分片的有效性。
//            // 当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
//            mergeMultipart(uploadId, objectName, partTagList);
//            uploadService.updateFileUpload(uploadId);
//        }


        return MultipartUploadRespDto.builder().isUpload(1)
                .partNumber(uploadPartRequest.getPartNumber())
                .uploadId(uploadPartRequest.getUploadId())
                .build();
    }
合并上传
    private CompleteMultipartUploadResult mergeMultipart(String uploadId, String objectName, List<PartETag> partTagList) {
        try {
            StopWatch st = new StopWatch();
            st.start();
            CompleteMultipartUploadRequest completeMultipartUploadRequest =
                    new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partTagList);
            log.info("{}文件上传完成,开始合并,partList:{}", uploadId, JSON.toJSON(partTagList));
            // 完成分片上传。

            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
            st.stop();
            log.info("{}文件上传完成,上传结果:{},耗时:{}", uploadId, JSON.toJSON(completeMultipartUploadResult), st.getTotalTimeMillis());
            return completeMultipartUploadResult;
        } catch (OSSException e) {
            e.printStackTrace();
            throw new BusinessException("合并失败:" + e.getMessage());
        } catch (com.aliyun.oss.ClientException e) {
            e.printStackTrace();
            throw new BusinessException("合并失败,客户端异常:" + e.getMessage());
        }
    }

    public CompleteMultipartUploadResult completeMultipartUpload(String uploadId) {
        FileUploadRecordEo uploadRecordEo = uploadService.findFileByUploadId(uploadId);
        if (uploadRecordEo == null) {
            throw new BusinessException("上传标识符异常!");
        }
        List<PartETag> partTagList = uploadService.findPartTagListByUploadId(uploadId);
        uploadService.updateFileUpload(uploadId);
        return mergeMultipart(uploadId, uploadRecordEo.getPaths(), partTagList);
    }

其他说明(视频截帧)

oss服务器提供了视频截帧功能,只需要在视频连接后拼上一段参数就能获取视频封面,
x-oss-process=video/snapshot,t_1000,f_jpg,w_0,h_0,m_fast,ar_auto
参数说明:
视频截帧参数说明
原始文档地址: 视频截帧
另外需要注意是,视频截帧功能是收费的,收费标准请参考oss收费标准

前端组件参考:前端大文件上传 - 分片上传
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
你可以使用 Element UI 和阿里云 OSS 来实现分片上传视频。首先,你需要在你的项目中引入 Element UI 组件库和阿里云 OSS 的 SDK。 然后,你可以使用 Element UI 中的上传组件来实现文件选择和上传的功能。在上传组件中,你可以设置一些参数来启用分片上传功能。例如,你可以设置 `chunkSize` 参数来指定每个分片的大小,以及 `chunkRetry` 参数来设置分片上传失败时的重试次数。 在上传过程中,你可以使用阿里云 OSS 的 SDK 来进行分片上传。你需要将视频文件切割成多个分片,并将每个分片上传阿里云 OSS 中的指定位置。可以使用 `oss.multipartUpload` 方法来实现分片上传功能。 具体的代码实现步骤如下: 1. 引入 Element UI 和阿里云 OSS 的 SDK: ```javascript import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import OSS from 'ali-oss'; ``` 2. 初始化阿里云 OSS 客户端: ```javascript const client = new OSS({ region: 'your_region', accessKeyId: 'your_access_key_id', accessKeySecret: 'your_access_key_secret', bucket: 'your_bucket_name' }); ``` 3. 在上传组件中设置分片上传参数: ```html <el-upload :action="your_upload_url" :on-success="handleSuccess" :chunk-size="your_chunk_size" :chunk-retry="your_chunk_retry" > <el-button slot="trigger">选择视频文件</el-button> </el-upload> ``` 4. 实现上传成功的回调函数: ```javascript handleSuccess(response, file, fileList) { // 在上传成功后,你可以根据需要进行后续处理,例如保存视频路径等操作 } ``` 5. 在回调函数中实现分片上传: ```javascript handleSuccess(response, file, fileList) { const { uploadId, name } = response.data; // 获取上传 ID 和文件名 const chunks = splitVideoIntoChunks(file); // 将视频文件切割成多个分片 const uploadPromises = chunks.map((chunk, index) => { return client.uploadPart(name, uploadId, index + 1, chunk); // 上传每个分片 }); Promise.all(uploadPromises) .then(results => { const etags = results.map(result => result.etag); return client.completeMultipartUpload(name, uploadId, etags); // 完成分片上传 }) .then(() => { console.log('分片上传完成'); }) .catch(error => { console.error('分片上传失败', error); }); } ``` 以上是一个简单的示例,你可以根据自己的需求进行适当调整。希望以上信息对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值