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

高效稳定:Spring Boot集成腾讯云OSS实现大文件分片上传与全路径获取

1.项目结构说明

src/main/java
├── com.example.oss
│   ├── config
│   │   ├── TencentCOSConfig.java       # OSS配置类
│   │   └── GlobalExceptionHandler.java # 全局异常处理
│   ├── controller
│   │   └── FileController.java         # 文件上传控制器
│   ├── properties
│   │   └── TencentCOSProperties.java   # 配置属性类
│   ├── service
│   │   └── COSUtils.java               # OSS工具类
│   └── OssApplication.java             # 启动类
resources
└── application.yml                     # 配置文件

 2.添加 Maven 依赖 (pom.xml)

<dependencies><!-- 腾讯云 OSS SDK --><dependency><groupId>com.qcloud</groupId><artifactId>cos_api</artifactId><version>5.6.154</version></dependency><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Configuration Processor --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- Lombok 简化代码 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>

3.配置文件 (application.yml)

server:port: 8080# 腾讯云OSS配置
tencent:cos:secret-id: AKIDz8krbsJ5yKBZQpn74WFkmLPx3*******  # 替换为你的SecretIdsecret-key: Gu5t9xGARNpq86cd98joQYCN3*******    # 替换为你的SecretKeyregion: ap-beijing                              # 存储桶地域bucket-name: your-bucket-1250000000             # 存储桶名称base-url: https://your-bucket.cos.ap-beijing.myqcloud.com # 基础URLmultipart-upload-threshold: 5242880             # 5MB分片阈值minimum-upload-part-size: 1048576               # 1MB最小分片thread-pool-core-size: 10                       # 核心线程数thread-pool-max-size: 50                        # 最大线程数# 文件上传大小限制
spring:servlet:multipart:max-file-size: 2GBmax-request-size: 2GB

4.配置属性类 (TencentCOSProperties.java)

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** 腾讯云OSS配置属性* 前缀: tencent.cos*/
@Data
@Component
@ConfigurationProperties(prefix = "tencent.cos")
public class TencentCOSProperties {// 访问密钥ID (从腾讯云控制台获取)private String secretId;// 访问密钥Key (从腾讯云控制台获取)private String secretKey;// 存储桶地域 (如: ap-beijing)private String region;// 存储桶名称private String bucketName;// 基础访问URLprivate String baseUrl;// 分片上传阈值 (默认5MB)private long multipartUploadThreshold = 5 * 1024 * 1024;// 最小分片大小 (默认1MB)private long minimumUploadPartSize = 1024 * 1024;// 线程池核心线程数private int threadPoolCoreSize = 10;// 线程池最大线程数private int threadPoolMaxSize = 50;
}

5.OSS 配置类 (TencentCOSConfig.java)

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.region.Region;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/*** 腾讯云OSS配置类*/
@Configuration
@RequiredArgsConstructor
public class TencentCOSConfig {private final TencentCOSProperties cosProperties;/*** 创建COS客户端*/@Beanpublic COSClient cosClient() {// 1. 初始化身份认证COSCredentials cred = new BasicCOSCredentials(cosProperties.getSecretId(), cosProperties.getSecretKey());// 2. 设置客户端配置ClientConfig clientConfig = new ClientConfig(new Region(cosProperties.getRegion()));clientConfig.setConnectionTimeout(30_000);      // 连接超时30秒clientConfig.setSocketTimeout(30_000);         // 读写超时30秒clientConfig.setMaxConnectionsCount(1024);     // 最大连接数// 3. 创建并返回COS客户端return new COSClient(cred, clientConfig);}/*** 创建分片上传线程池*/@Beanpublic ExecutorService cosTransferThreadPool() {return new ThreadPoolExecutor(cosProperties.getThreadPoolCoreSize(),cosProperties.getThreadPoolMaxSize(),60L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),new ThreadPoolExecutor.CallerRunsPolicy());}
}

6.OSS 工具类 (COSUtils.java)

import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.*;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.TransferManagerConfiguration;
import com.qcloud.cos.transfer.Upload;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Date;
import java.util.UUID;/*** 腾讯云OSS操作工具类*/
@Slf4j
@Component
@RequiredArgsConstructor
public class COSUtils {private final COSClient cosClient;private final TencentCOSProperties cosProperties;private final ExecutorService cosTransferThreadPool;/*** 普通文件上传* @param file 上传的文件* @return 文件访问URL*/public String uploadFile(MultipartFile file) {try {// 1. 生成唯一文件名并创建文件元数据String fileName = generateUniqueFileName(file.getOriginalFilename());ObjectMetadata metadata = createObjectMetadata(file);// 2. 创建上传请求PutObjectRequest request = new PutObjectRequest(cosProperties.getBucketName(),fileName,file.getInputStream(),metadata);// 3. 执行上传cosClient.putObject(request);// 4. 返回文件URLreturn getFullFileUrl(fileName);} catch (IOException e) {log.error("文件上传失败", e);throw new RuntimeException("文件上传失败: " + e.getMessage());}}/*** 自动分片上传(支持大文件)* @param file 上传的文件* @return 文件访问URL*/public String multipartUpload(MultipartFile file) {try {// 1. 创建临时文件Path tempPath = Files.createTempFile("cos-", getFileExtension(file));file.transferTo(tempPath);// 2. 生成唯一文件名String fileName = generateUniqueFileName(file.getOriginalFilename());// 3. 执行分片上传String fileUrl = doMultipartUpload(tempPath.toFile(), fileName);// 4. 删除临时文件Files.deleteIfExists(tempPath);return fileUrl;} catch (Exception e) {log.error("分片上传失败", e);throw new RuntimeException("分片上传失败: " + e.getMessage());}}/*** 获取文件完整URL* @param fileName OSS存储的文件名* @return 完整访问URL*/public String getFullFileUrl(String fileName) {// 处理特殊字符String encodedFileName = fileName.replace(" ", "%20");return cosProperties.getBaseUrl() + "/" + encodedFileName;}/*** 生成带签名的临时URL(默认1小时有效)* @param fileName OSS存储的文件名* @return 带签名的URL*/public String generatePresignedUrl(String fileName) {// 设置过期时间(1小时后)Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);// 生成预签名URLURL url = cosClient.generatePresignedUrl(cosProperties.getBucketName(),fileName,expiration);return url.toString();}// ============== 私有方法 ==============/*** 执行分片上传*/private String doMultipartUpload(File file, String fileName) {// 1. 创建分片上传管理器TransferManager transferManager = createTransferManager();try {// 2. 创建上传请求PutObjectRequest request = new PutObjectRequest(cosProperties.getBucketName(),fileName,file);// 3. 执行上传(自动分片)Upload upload = transferManager.upload(request);UploadResult result = upload.waitForUploadResult();// 4. 返回文件URLreturn getFullFileUrl(fileName);} catch (Exception e) {throw new RuntimeException("分片上传失败", e);} finally {// 5. 关闭分片上传管理器transferManager.shutdownNow();}}/*** 创建分片上传管理器*/private TransferManager createTransferManager() {TransferManager transferManager = new TransferManager(cosClient, cosTransferThreadPool);// 配置分片参数TransferManagerConfiguration config = new TransferManagerConfiguration();config.setMultipartUploadThreshold(cosProperties.getMultipartUploadThreshold());config.setMinimumUploadPartSize(cosProperties.getMinimumUploadPartSize());transferManager.setConfiguration(config);return transferManager;}/*** 创建文件元数据*/private ObjectMetadata createObjectMetadata(MultipartFile file) throws IOException {ObjectMetadata metadata = new ObjectMetadata();metadata.setContentLength(file.getSize());metadata.setContentType(file.getContentType());// 设置缓存控制(1年缓存)metadata.setHeader("Cache-Control", "max-age=31536000");return metadata;}/*** 生成唯一文件名*/private String generateUniqueFileName(String originalFilename) {// 获取文件扩展名String ext = getFileExtension(originalFilename);// 使用UUID + 时间戳生成唯一文件名return "files/" + UUID.randomUUID() + "-" + System.currentTimeMillis() + ext;}/*** 获取文件扩展名*/private String getFileExtension(String filename) {if (filename == null || !filename.contains(".")) {return "";}return filename.substring(filename.lastIndexOf("."));}
}

7.文件控制器 (FileController.java)

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;/*** 文件上传控制器*/
@RestController
@RequestMapping("/oss")
@RequiredArgsConstructor
public class FileController {private final COSUtils cosUtils;/*** 普通文件上传* @param file 上传的文件* @return 上传结果*/@PostMapping("/upload")public ApiResult uploadFile(@RequestParam("file") MultipartFile file) {try {String fileUrl = cosUtils.uploadFile(file);return ApiResult.success("文件上传成功", fileUrl);} catch (Exception e) {return ApiResult.fail("文件上传失败: " + e.getMessage());}}/*** 大文件分片上传* @param file 上传的文件* @return 上传结果*/@PostMapping("/multipart-upload")public ApiResult multipartUpload(@RequestParam("file") MultipartFile file) {try {String fileUrl = cosUtils.multipartUpload(file);return ApiResult.success("分片上传成功", fileUrl);} catch (Exception e) {return ApiResult.fail("分片上传失败: " + e.getMessage());}}/*** 获取文件URL* @param fileName OSS存储的文件名* @return 文件URL*/@GetMapping("/url")public ApiResult getFileUrl(@RequestParam String fileName) {try {String fileUrl = cosUtils.getFullFileUrl(fileName);return ApiResult.success(fileUrl);} catch (Exception e) {return ApiResult.fail("获取URL失败: " + e.getMessage());}}/*** 获取带签名的临时URL* @param fileName OSS存储的文件名* @return 临时URL*/@GetMapping("/presigned-url")public ApiResult getPresignedUrl(@RequestParam String fileName) {try {String presignedUrl = cosUtils.generatePresignedUrl(fileName);return ApiResult.success(presignedUrl);} catch (Exception e) {return ApiResult.fail("生成临时URL失败: " + e.getMessage());}}
}/*** 统一API响应结构*/
record ApiResult<T>(int code, String message, T data) {public static ApiResult<Object> success(Object data) {return new ApiResult<>(200, "success", data);}public static ApiResult<Object> success(String message, Object data) {return new ApiResult<>(200, message, data);}public static ApiResult<Object> fail(String message) {return new ApiResult<>(500, message, null);}
}

8.全局异常处理 (GlobalExceptionHandler.java)

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;/*** 全局异常处理器*/
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 文件大小超限异常处理*/@ExceptionHandler(MaxUploadSizeExceededException.class)public ApiResult handleSizeExceeded() {return ApiResult.fail("文件大小超过限制");}/*** 通用异常处理*/@ExceptionHandler(Exception.class)public ApiResult handleException(Exception e) {return ApiResult.fail("服务异常: " + e.getMessage());}
}

9.最佳实践建议

  1. 安全优化

    // 在控制器中添加文件类型校验
    @PostMapping("/upload")
    public ApiResult uploadFile(@RequestParam("file") MultipipartFile file) {if (!isValidFileType(file)) {return ApiResult.fail("不支持的文件类型");}// ...
    }private boolean isValidFileType(MultipartFile file) {String[] allowedTypes = {"image/jpeg", "application/pdf"};return Arrays.asList(allowedTypes).contains(file.getContentType());
    }
  2. 存储优化

    // 按日期分目录存储
    private String generateUniqueFileName(String originalFilename) {String dateDir = new SimpleDateFormat("yyyyMMdd").format(new Date());return dateDir + "/" + UUID.randomUUID() + getFileExtension(originalFilename);
    }
  3. 性能优化

    # 调整线程池配置(高并发场景)
    tencent:cos:thread-pool-core-size: 20thread-pool-max-size: 200
  4. 监控建议

    // 添加上传耗时监控
    long start = System.currentTimeMillis();
    String url = cosUtils.uploadFile(file);
    long duration = System.currentTimeMillis() - start;
    log.info("文件上传完成,耗时: {}ms", duration);

http://www.dtcms.com/a/315632.html

相关文章:

  • systemui 的启动流程是怎么样的?
  • 深入浅出 RabbitMQ-交换机详解与发布订阅模型实战
  • 软件版本、Nodejs中 ~、*、^
  • centos7 个人网站搭建之gitlab私有化部署实现线上发布
  • 鸿蒙OS 系统安全
  • 14.Linux : nfs与autofs的使用
  • 计算机基础速通--数据结构·栈与队列应用
  • 国内外大模型体验与评测技术
  • 安科瑞智慧能源管理系统在啤酒厂5MW分布式光伏防逆流控制实践
  • 【深度学习新浪潮】混元3D是什么产品?
  • 大模型之后,机器人正在等待它的“GPT-1 时刻”
  • BOM Cookie操作详解
  • 基于Halcon 3D的手眼标定方法
  • Kafka自动消费消息软件(自动化测试Kafka)
  • OneCode 3.0 前端架构全面研究
  • xxl-job配置相同,执行顺序
  • Android WiFi图标显示感叹号解决方法
  • Linux 线程同步与互斥
  • 链表之leetcode19:删除链表的倒数第N个结点
  • LeetCode 71~90题解
  • 危化品运输误检率↓83%!陌讯多模态融合算法在油罐车识别的工程实践
  • 机器学习③【模型训练、K近邻算法(KNN)、贝叶斯算法(Navie Bayes)、模型调优】
  • 基于 Ubuntu 的 Linux 系统中 Vivado 2020.1 下载安装教程
  • Linux操作系统从入门到实战(十三)版本控制器Git基础概念讲解
  • Qwen Image:开源中文渲染SOTA,重塑文生图技术边界
  • Spring Boot 整合 Web 开发全攻略
  • 机器学习Adaboost算法----SAMME算法和SAMME.R算法
  • AI+OA原生应用 麦当秀AIPPT
  • Day34 GPU训练及类的call方法
  • 【ESP32学习笔记】环境搭建和HelloEsp32