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

news2025/1/20 6:02:35

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

因此,追求用户体验的项目可能会考虑使用第三方的云服务来实现存储,目前市场上主流的厂商有:七牛云、阿里云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测试上传接口,成功返回地址。使用浏览器打开该返回地址,可以正常预览。


总结

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/93017.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Tomcat安装配置全解

&#x1f44c; 棒棒有言&#xff1a;也许我一直照着别人的方向飞&#xff0c;可是这次&#xff0c;我想要用我的方式飞翔一次&#xff01;人生&#xff0c;既要淡&#xff0c;又要有味。凡事不必太在意&#xff0c;一切随缘&#xff0c;缘深多聚聚&#xff0c;缘浅随它去。凡事…

数据库分库分表

文章目录为什么要分库分表&#xff1f;数据切分垂直切分水平切分&#xff08;每个表的结构相同&#xff09;范围拆分取模拆分&#xff08;一般为业务主键&#xff09;分库分表带来的问题数据倾斜问题热点问题事务问题聚合查询问题分页问题非分区业务查询分库分表实现或工具hash…

DSP篇--C6701功能调试系列之 UART串口测试

目录 1、原理 2、测试 调试的前期准备可以参考前面的博文&#xff1a;DSP篇--C6701功能调试系列之前期准备_nanke_yh的博客-CSDN博客 UART串口收发数据存在两种模式&#xff1a;通常的串口模式&#xff08;McBSP in Serial Port Mode&#xff09;和GPIO模式&#xff08;McBS…

哈希表及其与Java类集的关系

目录 1.哈希表的概念 2.哈希冲突 3.如何避免哈希冲突? 3.1哈希函数设计 3.2 负载因子的调节 4.解决哈希冲突 4.1闭散列 4.1.1线性探测 4.1.2二次探测 4.2开散列(哈希桶) 5.HashMap 6.HashSet 1.哈希表的概念 假设有一组数据,要让你去搜索其中的一个关键码,这种场…

JWT快速入门及所需依赖

目录 1.JWT 1.1什么是JWT 1.2JWT的构成 jwt的头部 payload signature 1.3JWT快速入门案例 2Jwt认证&#xff08;微服务&#xff09; 2.1微服务下统一权限认证 2.2应用认证 3.无状态的JWT令牌如何实现续签功能&#xff1f; 3.1不允许改变Token令牌实现续签 3.2允许改…

计算机毕业设计django基于python大学生多媒体学习系统

项目介绍 随着计算机多媒体技术的发展和网络的普及。采用当前流行的B/S模式以及3层架构的设计思想通过Python技术来开发此系统的目的是建立一个配合网络环境的大学生多媒体学习系统的平台,这样可以有效地解决数据学习系统混乱的局面。 本文首先介绍了大学生多媒体学习系统的发…

eslint Parsing error: The keyword ‘export‘ is reserved

报错 原因 ECMAScript modules(import/export) 是 es6 的语法。 根据 eslint 官方文档 Configure language options &#xff0c;eslint 默认使用 es5 语法&#xff1a; 解决 要让 eslint 知道我在使用 es6 的 modules 语法。有下面几种方法&#xff1a; 设置 env 为 es6&am…

喜讯 | 第三届国际科创节,企企通喜提两项大奖

近日&#xff0c;第三届国际科创节暨数服会STIF奖评选活动重磅揭晓&#xff0c;旨在向科技创新与数字化转型引领者致敬。企企通作为作为数字化采购平台领军者&#xff0c;凭借业内领先的技术实力与优秀的服务口碑&#xff0c;经过层层筛选和专业评审&#xff0c;企企通最终荣膺…

【LeetCode每日一题:1785. 构成特定和需要添加的最少元素~~~数组公式推导+防止整型溢出+向上取整+贪心】

题目描述 给你一个整数数组 nums &#xff0c;和两个整数 limit 与 goal 。数组 nums 有一条重要属性&#xff1a;abs(nums[i]) < limit 。 返回使数组元素总和等于 goal 所需要向数组中添加的 最少元素数量 &#xff0c;添加元素 不应改变 数组中 abs(nums[i]) < limi…

内存管理:虚拟地址空间和堆

准备用一个系列来总结一下内存管理涉及到的相关知识&#xff0c;范围从底层的数据结构和算法&#xff0c;到上层的API的使用&#xff0c;这里的内存管理&#xff0c;目前打算主要是侧重在堆的管理&#xff0c;本文作为一个引子&#xff0c;先粗略讲一下虚拟地址空间、堆管理、a…

​合并PDF文件什么方法很简单?看完你就明白了

想要将几个PDF文件合并到一起&#xff0c;什么方法使用起来是很简单的呢&#xff1f;PDF文件作为大家经常使用的文件之一&#xff0c;对它的编辑需求也很多&#xff0c;除了需要编辑文件的内容之外&#xff0c;还有需要将几个文件合并到一起使用的需求。那么我们如果遇到这种情…

traffic-forward

traffic-forward traffic-forward 是一款python开发的流量转发工具&#xff0c;可以使用python脚本行运行&#xff0c;也可以封装使用命令行&#xff0c;同样可以使用pyinstaller等工具进行封装成Macos&#xff0c;Linux, Windows 下的可执行文件运行&#xff0c;可用于本地流量…

简单理解HTML区块_HTML学习第七篇区块元素和内联元素

简单理解HTML区块_区块元素和内联元素HTML篇_第七章、区块一、区块元素和内联元素1.1块级元素1.2内联元素二、<div>元素三、<span>元素HTML篇_第七章、区块 一、区块元素和内联元素 HTML元素可以通过<div>和<span>元素组合起来&#xff0c;大多数 HT…

固定行数的纵向分栏

【问题】 what can ı configure the jasper report detail heapriider layout ? ı want to print datas side by side and every sides have 4 datas sub bottom 1 data1 5 data5 2 data2 6 data6 3 data3 4 data4 【回答】 整张报表纵向分栏可在 jasper 中设置分栏数&a…

性能高、上手快,实体类转换工具 MapStruct 到底有多强大

1.什么是MapStruct 1.1 JavaBean 的困扰 对于代码中 JavaBean之间的转换&#xff0c; 一直是困扰我很久的事情。在开发的时候我看到业务代码之间有很多的 JavaBean 之间的相互转化&#xff0c; 非常的影响观感&#xff0c;却又不得不存在。我后来想的一个办法就是通过反射&…

用Quasar开发Vue3+Electron跨平台应用的简单指南

1. 前言 Quasar是一个开源的vue.js基础框架&#xff0c;简单配置即可在其基础上进行SPA, SSR, PWA, 手机网站以及跨平台应用程序的开发&#xff0c;本文将简述如何基于Quasar Vue3 Vite Electron进行桌面应用开发。 2. 配置流程 2.1 框架构建 首先&#xff0c;在要存放代…

『NLP学习笔记』NER任务的CRF-layer的原理

NER任务的CRF-layer的原理 文章目录一. 预备工作二. BILSTM-CRF模型2.1. BiLSTM层输出2.2. 如果没有CRF层会怎么样2.3. CRF层可以从训练数据中学到约束三. CRF层3.1. 发射(Emission)分数3.2. 转移(Transition)分数3.3. CRF损失函数3.4. 实际路径得分3.5. 所有可能的路径的得分…

Ac-EEVVAC-pNA,389868-12-6

Ac-EEVVAC-pNA, chromogenic substrate for a continuous spectrophotometric assay of HCV NS3 protease. The sequence EEVVAC is derived from the 5A-5B cleavage junction of the HCV polyprotein. Ac-EEVVAC-pNA, HCV NS3蛋白酶连续分光光度法测定的显色底物。EEVVAC序列…

FPGA驱动24C04实现读写操作,提供工程源码和技术支持

目录1.24c04芯片手册解读2.纯verilog的i2c驱动3.24c04读写状态机设计4.上板调试验证5.福利&#xff1a;工程源码获取1.24c04芯片手册解读 24c04芯片手册很简单&#xff0c;原理图设计页很简单&#xff0c;这里只说代码设计需要注意的点&#xff1a; 1、写操作延时周期大于等于…

嵌入式软件工程师技能树——Linux应用编程+网络编程+驱动开发+操作系统+计算机网络

文章目录Linux驱动开发1、Linux内核组成2、用户空间与内核的通讯方式有哪些&#xff1f;3、系统调用read/write流程4、内核态用户态的区别5、bootloader内核 根文件的关系6、BootLoader的作用7、BootLoader两个启动阶段1、汇编实现&#xff0c;完成依赖于CPU体系架构的设置&…