likes
comments
collection

文件上传,还存储在应用服务器?

作者站长头像
站长
· 阅读数 10

本文正在参加「金石计划 . 瓜分6万现金大奖」

前言

嗨,大家好,我是希留,一个被迫致力于全栈开发的老菜鸟。

一般项目开发中都会有文件、图片、视频等文件上传并能够访问的场景。要实现这样的场景,要么把文件存储在应用服务器上,要么搭建文件服务来存储。但是这两种方式也有不少的缺点,增加运维的成本。

因此,追求用户体验的项目可能会考虑使用第三方的云服务来实现存储,目前市场上主流的厂商有:七牛云、阿里云OSS、腾讯云COS等,具体采用哪种存储方案还需结合项目的规模、成本等因素,综合考量。

因为我的是腾讯云的服务器,所以就直接开通了腾讯云的COS对象存储。这篇文章就来记录一下,SpringBoot整合腾讯云COS对象存储实现文件上传的。


一、准备工作

整合前需要做一些准备工作,开通COS对象存储,创建存储通,创建访问密钥。

1. 开通腾讯云对象存储服务

新用户专享,1米可以购买1年的存储。用来学习还是很香的。console.cloud.tencent.com/cos 文件上传,还存储在应用服务器?

2. 创建存储桶

注意存储桶访问的访问权限,设置成公有读私有写。 文件上传,还存储在应用服务器? 文件上传,还存储在应用服务器?

3. 密钥管理,创建密钥

点击新建密钥,会自动生成。 文件上传,还存储在应用服务器? 文件上传,还存储在应用服务器?

三、整合步骤

1. 添加maven依赖

代码如下(示例):

<!--腾讯云 COS 对象存储-->
<dependency>
	<groupId>com.qcloud</groupId>
	<artifactId>cos_api</artifactId>
	<version>5.6.89</version>
</dependency>

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测试上传接口,成功返回地址。使用浏览器打开该返回地址,可以正常预览。 文件上传,还存储在应用服务器? 文件上传,还存储在应用服务器?


总结

以上就是本文的全部内容了,感谢大家的阅读。

如果觉得文章对你有帮助,还不忘帮忙点赞、收藏、关注、评论哟,您的支持就是我创作最大的动力!