当前位置: 首页 > news >正文

Spring Boot + Vue2 实现腾讯云 COS 文件上传:从零搭建分片上传系统

目录

一、项目目标

二、腾讯云 COS 基本配置

1. 创建存储桶

2. 获取 API 密钥

3. 设置跨域规则(CORS)

三、后端(Spring Boot)实现

1. 依赖配置

2. 配置腾讯云 COS(application.yml)

3. 初始化 COS 客户端

4. 文件上传接口

(1)普通上传

(2)分片上传接口

① 初始化分片上传

② 上传分片

③ 合并分片

四、前端(Vue2)实现

1. 安装依赖

2. 分片上传逻辑

五、注意事项与优化

1. 分片大小限制

2. 并发上传优化

3. 断点续传支持

4. 安全性增强

六、总结

一、项目目标

实现基于腾讯云 COS 的 大文件分片上传普通文件上传 功能,前后端分离架构,采用 Vue2 + Spring Boot + YML 配置方式,并覆盖以下注意事项:

  • 分片上传大小限制
  • 并发上传优化
  • 断点续传支持
  • 安全性增强(避免暴露密钥)
  • 跨域规则配置(CORS)

二、腾讯云 COS 基本配置

1. 创建存储桶

登录腾讯云控制台 → 对象存储 COS → 创建存储桶:

  • 存储桶名称:your-bucket-name-1250000000
  • 地域:ap-beijing(根据需求选择)
  • 权限设置:私有读写

2. 获取 API 密钥

前往 API 密钥管理 页面,创建或使用已有 SecretId/SecretKey。

安全建议:前端禁止直接使用 SecretId/SecretKey,应通过后端代理或使用 STS 临时密钥。

3. 设置跨域规则(CORS)

前往 权限管理 → 跨域规则,添加以下规则:

{"allowedOrigin": ["*"],"allowedMethod": ["GET", "POST", "PUT", "HEAD"],"allowedHeader": ["*"],"exposeHeader": [],"maxAgeSeconds": 3000
}

三、后端(Spring Boot)实现

1. 依赖配置

<dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 腾讯云 COS SDK --><dependency><groupId>com.qcloud</groupId><artifactId>cos_api</artifactId><version>5.2.4</version></dependency><!-- 工具类 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency>
</dependencies>

2. 配置腾讯云 COS(application.yml

tencent:cos:secret-id: YOUR_SECRET_IDsecret-key: YOUR_SECRET_KEYregion: ap-beijingbucket-name: your-bucket-name-1250000000

3. 初始化 COS 客户端

import com.qcloud.cos.COSClient;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.region.Region;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class CosConfig {@Value("${tencent.cos.secret-id}")private String secretId;@Value("${tencent.cos.secret-key}")private String secretKey;@Value("${tencent.cos.region}")private String region;@Beanpublic COSClient cosClient() {COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);Region cosRegion = new Region(region);return new COSClient(cred, cosRegion);}
}

4. 文件上传接口

(1)普通上传
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.PutObjectRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;
import java.util.UUID;@RestController
@RequestMapping("/api/upload")
public class UploadController {@Autowiredprivate COSClient cosClient;@Value("${tencent.cos.bucket-name}")private String bucketName;@PostMapping("/simple")public String simpleUpload(@RequestParam("file") MultipartFile file) {try {String remoteFileName = "uploads/" + UUID.randomUUID().toString() + "-" + file.getOriginalFilename();InputStream inputStream = file.getInputStream();PutObjectRequest request = new PutObjectRequest(bucketName, remoteFileName, inputStream, null);cosClient.putObject(request);return "https://" + bucketName + ".cos." + cosClient.getClientConfig().getRegion().getName() + ".myqcloud.com/" + remoteFileName;} catch (Exception e) {return "上传失败: " + e.getMessage();}}
}
(2)分片上传接口
① 初始化分片上传
@PostMapping("/init")
public String initMultipartUpload(@RequestParam String fileName) {try {InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, fileName);return cosClient.initiateMultipartUpload(request).getUploadId();} catch (Exception e) {return "初始化失败: " + e.getMessage();}
}
② 上传分片
@PostMapping("/part")
public String uploadPart(@RequestParam("file") MultipartFile file,@RequestParam("uploadId") String uploadId,@RequestParam("partNumber") int partNumber,@RequestParam("fileName") String fileName) {try {UploadPartRequest request = new UploadPartRequest().withBucketName(bucketName).withKey(fileName).withUploadId(uploadId).withPartNumber(partNumber).withInputStream(file.getInputStream()).withPartSize(file.getSize());return cosClient.uploadPart(request).getETag(); // 返回 ETag} catch (Exception e) {return "分片上传失败: " + e.getMessage();}
}
③ 合并分片
@PostMapping("/complete")
public String completeMultipartUpload(@RequestParam("fileName") String fileName,@RequestParam("uploadId") String uploadId,@RequestParam("partETags") List<String> partETags) {try {List<PartETag> partETagList = partETags.stream().map(etag -> new PartETag(partETags.indexOf(etag) + 1, etag)).toList();CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(bucketName, fileName, uploadId, partETagList);cosClient.completeMultipartUpload(request);return "https://" + bucketName + ".cos." + cosClient.getClientConfig().getRegion().getName() + ".myqcloud.com/" + fileName;} catch (Exception e) {return "合并失败: " + e.getMessage();}
}

四、前端(Vue2)实现

1. 安装依赖

npm install axios

2. 分片上传逻辑

<template><div><input type="file" @change="handleFileChange" /><button @click="uploadFile">上传</button><div>上传进度: {{ progress }}%</div></div>
</template><script>
import axios from 'axios';export default {data() {return {file: null,uploadId: '',chunkSize: 5 * 1024 * 1024, // 5MBprogress: 0,uploadedChunks: [], // 已上传的分片索引};},methods: {handleFileChange(event) {this.file = event.target.files[0];this.uploadedChunks = [];this.progress = 0;},async uploadFile() {if (!this.file) {alert("请选择文件");return;}// 1. 初始化分片上传const initRes = await axios.post('/api/upload/init', {fileName: this.file.name,});this.uploadId = initRes.data;// 2. 并发上传分片const totalChunks = Math.ceil(this.file.size / this.chunkSize);const promises = [];for (let i = 0; i < totalChunks; i++) {const start = i * this.chunkSize;const end = Math.min(start + this.chunkSize, this.file.size);if (this.uploadedChunks.includes(i)) continue; // 跳过已上传分片const chunk = this.file.slice(start, end);const formData = new FormData();formData.append('file', chunk);formData.append('uploadId', this.uploadId);formData.append('partNumber', i + 1);formData.append('fileName', this.file.name);const promise = axios.post('/api/upload/part', formData, {onUploadProgress: (progressEvent) => {const percent = Math.round(((this.uploadedChunks.length * 100) / totalChunks) +((progressEvent.loaded / progressEvent.total) * 100 / totalChunks));this.progress = percent;},});promises.push(promise.then(() => {this.uploadedChunks.push(i); // 标记为已上传}));}// 并发上传await Promise.all(promises);// 3. 合并分片const completeRes = await axios.post('/api/upload/complete', {fileName: this.file.name,uploadId: this.uploadId,partETags: [], // 后端应返回每个分片的 ETag});alert("上传成功: " + completeRes.data);},},
};
</script>

五、注意事项与优化

1. 分片大小限制

  • 腾讯云要求 单个分片最小 1MB,最大 5GB
  • 推荐设置 chunkSize = 5 * 1024 * 1024(5MB)。

2. 并发上传优化

  • 使用 Promise.all 实现并发上传,提升上传效率。
  • 可设置最大并发数,避免过多请求导致服务器压力过大。

3. 断点续传支持

  • 通过 this.uploadedChunks 记录已上传分片索引。
  • 重启上传时跳过已上传部分,实现断点续传。

4. 安全性增强

  • 禁止前端暴露 SecretId/SecretKey
  • 建议使用 STS 临时密钥 或 后端代理上传
    • 后端可封装上传逻辑,前端仅调用后端接口上传文件。
    • 使用腾讯云 STS 获取临时密钥,设置访问权限和有效期。

六、总结

本教程完整实现了基于 Spring Boot + Vue2 的腾讯云 COS 文件上传功能,支持:

  • 普通上传
  • 大文件分片上传(支持并发、断点续传)
  • 安全性增强(密钥不暴露)
  • 跨域规则配置(CORS)

可根据实际业务需求进一步扩展,如添加上传进度持久化、上传失败重试机制等。

http://www.lryc.cn/news/588156.html

相关文章:

  • QT——信号与槽
  • Zabbix在MySQL性能监控方面的运用
  • 闲庭信步使用图像验证平台加速FPGA的开发:第十五课——基于sobel算子边缘检测的FPGA实现
  • Spring核心概念指南
  • Linux部署Mysql
  • (LeetCode 每日一题) 1290. 二进制链表转整数 (链表+二进制)
  • 微前端框架深度对决:qiankun、micro-app、wujie 技术内幕与架构选型指南
  • 艺术总监的构图“再造术”:用PS生成式AI,重塑照片叙事框架
  • 网络协议和基础通信原理
  • Bash vs PowerShell | 从 CMD 到跨平台工具:Bash 与 PowerShell 的全方位对比
  • 隐藏源IP的核心方案与高防实践
  • VNC和Socket
  • IP相关
  • 水务工程中自动化应用:EtherNet/IP转PROFIBUS DP连接超声波流量计
  • 从0到1实现Shell!Linux进程程序替换详解
  • 创客匠人谈知识变现:IP 变现的核心,在于执行闭环的落地
  • 更改elementui 图标 css content
  • 修改crontab默认编辑器
  • 多线程是如何保证数据一致和MESI缓存一致性协议
  • 一种用于医学图像分割的使用了多尺寸注意力Transformer的混合模型: HyTransMA
  • 从“有”到“优”:iPaaS 赋能企业 API 服务治理建设
  • FastAPI-P1:Pydantic模型与参数额外信息
  • Linux中使用云仓库上传镜像和私库制作Registry
  • Android系统的问题分析笔记 - Android上的调试方式 debuggerd
  • 超导探索之术语介绍:费曼图(Feynman Diagram)
  • 【基础架构】——架构设计流程第三步(评估和选择备选方案)
  • 8.服务通信:Feign深度优化 - 解密声明式调用与现代负载均衡内核
  • 现代数据平台能力地图:如何构建未来数据平台的核心能力体系
  • LSV负载均衡
  • org.casic.javafx.control.PaginationPicker用法