前言
大家好,我是石流,一个被迫投身全栈开发的老菜鸟。
在一般的项目开发中,都会有文件、图片、视频等文件上传访问的场景。要实现这样的场景,要么将文件存储在应用服务器上存储服务器搭建,要么构建一个文件服务来存储它。但是,这两种方式也有很多缺点,增加了运维成本。
因此,追求用户体验的项目可以考虑使用第三方云服务来实现存储。目前市场主流厂商包括:七牛云、阿里云OSS、腾讯云COS等,具体采用何种存储方案需要结合项目规模、成本等因素综合考虑。
因为我的是腾讯云服务器,所以我直接激活了腾讯云的COS对象存储。本文将记录SpringBoot集成腾讯云COS对象存储实现文件上传。
一、准备工作
在集成之前,需要做一些准备工作存储服务器搭建,比如激活 COS 对象存储、创建存储通证、创建访问密钥等。
1.开启腾讯云对象存储服务
新用户专属,1米可买1年存储。读书还是很香的。console.cloud.tencent.com/cos
2.创建一个桶
注意bucket access的访问权限,设置为public read和private write。
3.密钥管理,创建密钥
点击New Key,会自动生成。
三、集成步骤一、添加maven依赖
代码如下(示例):
com.qcloud
cos_api
5.6.89
复制代码
2.在yml文件中添加配置
代码如下(示例):
# 腾讯云cos配置
cos:
baseUrl: https://xiliu-******24.cos.ap-guangzhou.myqcloud.com
secretId: AKI******************ior
secretKey: zZ*************z6
regionName: ap-guangzhou
bucketName: xiliu-******24
folderPrefix: /upload
复制代码
3.新建COS配置类
代码如下(示例):
package com.java.xiliu.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author xiliu
* @description 腾讯云cos对象存储配置类
* @date 2022/10/28
*/
@Data
@Component
@ConfigurationProperties(prefix = "cos")
public class CosConfig {
/**
* 存储桶访问路径
**/
private String baseUrl;
/**
* 腾讯云账号秘钥
**/
private String secretId;
/**
* 密码秘钥
**/
private String secretKey;
/**
* 存储桶地区
**/
private String regionName;
/**
* 存储桶名称
**/
private String bucketName;
/**
* 上传的根目录
**/
private String folderPrefix;
public COSClient getCosClient() {
// 初始化用户信息
COSCredentials cosCredentials = new BasicCOSCredentials(this.secretId,this.secretKey);
// 设置地域
Region region = new Region(this.regionName);
ClientConfig config = new ClientConfig(region);
// 生成COS客户端
COSClient client = new COSClient(cosCredentials,config);
return client;
}
}
复制代码
4.新建COS上传工具类
代码如下(示例):
package com.java.xiliu.common.untils.file;
import com.java.xiliu.common.untils.SpringUtils;
import com.java.xiliu.config.CosConfig;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.UploadResult;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author xiliu
* @description 腾讯云COS文件上传工具类
* @date 2022/10/31
*/
@Slf4j
public class CosClientUtils {
/**
* 获取配置信息
*/
private static CosConfig cosConfig = SpringUtils.getBean(CosConfig.class);
public static String upload(MultipartFile file, String dir) throws Exception {
String originalFilename = file.getOriginalFilename();
// 文件名
String name = FilenameUtils.getBaseName(originalFilename) + "_" + System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));
// 目录
String folderName = cosConfig.getFolderPrefix() + "/" + dir + "/";
String key = folderName + name;
File localFile = null;
try {
localFile = transferToFile(file);
String filePath = uploadFileToCos(localFile, key);
log.info("upload COS successful: {}", filePath);
return filePath;
} catch (Exception e) {
throw new Exception("文件上传失败");
} finally {
localFile.delete();
}
}
/**
* 用缓冲区来创建临时文件
* 使用 MultipartFile.transferTo()
* @param multipartFile
* @return
*/
private static File transferToFile(MultipartFile multipartFile) throws IOException {
String originalFilename = multipartFile.getOriginalFilename();
String prefix = originalFilename.split("\.")[0];
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
File file = File.createTempFile(prefix, suffix);
multipartFile.transferTo(file);
return file;
}
/**
* 上传文件到COS
* @param localFile
* @param key
* @return
*/
private static String uploadFileToCos(File localFile, String key) throws InterruptedException {
PutObjectRequest putObjectRequest = new PutObjectRequest(cosConfig.getBucketName(), key, localFile);
// 获取连接
COSClient cosClient = cosConfig.getCosClient();
// 创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(8, 16,
4, TimeUnit.SECONDS, new ArrayBlockingQueue(10), new ThreadPoolExecutor.AbortPolicy());
// 传入一个threadPool, 若不传入线程池, 默认TransferManager中会生成一个单线程的线程池
TransferManager transferManager = new TransferManager(cosClient, threadPool);
// 返回一个异步结果Upload, 可同步的调用waitForUploadResult等待upload结束, 成功返回UploadResult, 失败抛出异常
Upload upload = transferManager.upload(putObjectRequest);
UploadResult uploadResult = upload.waitForUploadResult();
transferManager.shutdownNow();
cosClient.shutdown();
String filePath = cosConfig.getBaseUrl() + uploadResult.getKey();
return filePath;
}
}
复制代码
5.新建Controller上传接口
代码如下(示例):
@ApiOperation(value = "用户头像上传")
@PostMapping("/profile/avatar")
public R uploadAvatar(@RequestParam("avatarfile") MultipartFile file) throws Exception {
if (!file.isEmpty()) {
String avatar = CosClientUtils.upload(file, "avatar");
return R.ok(avatar);
}
return R.error("上传头像异常,请联系管理员");
}
复制代码
6.测试
使用Swagger接口文档或Postman测试上传接口,成功返回地址。用浏览器打开返回地址,可以正常预览。