Spring Boot 集成阿里云OSS 完成文件上传下载
前言:
文件上传下载在项目开发中是一个非常常见的业务场景,在云服务上还没有兴起的时候,一般来说都会把文件单独存放到文件服务器上,随着云服务的兴起,各类云服务厂商都提供了 OSS 服务,本篇我们分享 Spring Boot 项目如何把文件存储到阿里云 OSS。
Spring Boot 集成阿里云 OSS
阿里云提供了 SDK,项目中引入相关依赖即可,我们在 pom.xml 文件中引入依赖如下:
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version>
</dependency>
阿里云访问信息
阿里云访问信息有四个如下:
- Endpoint:OSS服务所在地域的访问域名。
- AccessKeyId:访问OSS服务的密钥ID。
- AccessKeySecret:访问OSS服务的密钥秘钥。
- BucketName:您创建的存储空间名称。
阿里云 OSS 上传下载工具类
根据阿里云的访问要求封装了阿里云 OSS 上传下载工具类,如下:
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.comm.Protocol;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.PutObjectRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Date;/*** @ClassName: AliyunOssUtil* @Author: Author* @Date: 2024/11/13 19:39* @Description:*/
@Slf4j
@Component
public class AliyunOssUtil {@Value("${aliyun.oss.endpoint}")private String endpoint;@Value("${aliyun.oss.accessKeyId}")private String accessKeyId;@Value("${aliyun.oss.accessKeySecret}")private String accessKeySecret;@Value("${aliyun.oss.bucketName}")private String bucketName;/*** @return com.aliyun.oss.ClientBuilderConfiguration* @description 获取配置类*/public ClientBuilderConfiguration getConfig() {// ClientBuilderConfiguration是OSSClient的配置类,可配置代理、连接超时、最大连接数等参数。ClientBuilderConfiguration conf = new ClientBuilderConfiguration();// 设置从连接池中获取连接的超时时间(单位:毫秒),默认不超时。conf.setConnectionRequestTimeout(3000);// 设置连接空闲超时时间。超时则关闭连接,默认为60000毫秒。conf.setIdleConnectionTime(30000);conf.setProtocol(Protocol.HTTPS);return conf;}/*** @param file:* @param fileName:* @return java.lang.String* @description*/public String uploadOssFile(File file, String fileName) throws IOException {// 获取上传的文件的输入流InputStream in = new FileInputStream(file);PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, in);String fileUrl = null;// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, getConfig());try {// 上传文件ossClient.putObject(putObjectRequest);// 获取文件访问路径Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 100);URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration);//url 解码 返回的地址需要进行 URL 解码fileUrl = URLDecoder.decode(url.toString(), "UTF-8");} catch (OSSException e) {log.error("oss上传文件失败,异常信息:", e);} finally {if (ossClient != null) {// 关闭ossClientossClient.shutdown();}}return fileUrl;}/*** @param fileUrl:* @param fileName:* @return java.io.File* @description*/public File downLoadOssFile(String fileUrl, String fileName) throws IOException {OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, getConfig());File file = new File(fileName);if (!file.exists()) {file.createNewFile();}String[] array = fileUrl.split("[?]");fileUrl = array[0];//key 填写不包含 Bucket 名称在内的路径 例如 testfolder/mytest.xlsxString key = fileUrl.substring(fileUrl.lastIndexOf(StrUtil.SLASH) + 1);ossClient.getObject(new GetObjectRequest(bucketName, key), file);ossClient.shutdown();return file;}/*** oss中文件是否存在** @param fileName* @return*/public Boolean isFileExist(String fileName) {// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, getConfig());Boolean result = Boolean.FALSE;try {result = ossClient.doesObjectExist(bucketName, fileName);} catch (OSSException oe) {log.error("oss检验文件是否存在失败,Error Message:{},Error Code:{}", oe.getMessage(), oe.getErrorCode());} finally {if (ossClient != null) {// 关闭ossClientossClient.shutdown();}}return result;}/*** 删除oss文件** @param fileName*/public void deleteFile(String fileName) {// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, getConfig());try {// 删除文件ossClient.deleteObject(bucketName, fileName);} catch (OSSException oe) {log.error("oss删除文件失败,Error Message:{},Error Code:{}", oe.getMessage(), oe.getErrorCode());} finally {if (ossClient != null) {// 关闭ossClientossClient.shutdown();}}}}
业务场景
业务场景要求用户端发起导出请求后,快速生成一个导出记录响应到用户端,后端异步完成导出操作,后端完成导出后,将导出的文件上传到阿里云 OSS,用户可以在页面完成文件的下载。
前面我们已经封装好了阿里云 OSS 的工具类,这里我们实现整个业务,调用 OSS 工具类完成文件的上传下载即可。
Service 代码如下
部分项目中的代码没有展示出来,了解整体实现思路即可。。
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*** @ClassName: FileServiceImpl* @Author: Author* @Date: 2024/11/13 19:39* @Description:*/
@Slf4j
@Service
public class FileServiceImpl implements IFlieService {@Autowiredprivate AibabaCloudFileMapper aibabaCloudFileMapper;@Autowiredprivate AliyunOssUtil aliyunOssUtil;//前面我们已经封装好了阿里云 OSS 的工具类,这里我们实现整个业务,调用 OSS 工具类完成文件的上传下载即可。@Transactional(rollbackFor = Exception.class)@Overridepublic void exportList(FileQueryDTO fileQueryDTO) {List<SourceCodeAnalysisExportVO> exportList = new ArrayList<>();//导出记录落库AlibabaCloudFileDO alibabaCloudFileDO = new AlibabaCloudFileDO();//文件业务类型alibabaCloudFileDO.setBusinessType(1);//文件生成中alibabaCloudFileDO.setFileStatus(1);String fileName = "导出学生成绩单" + DateUtil.format(new Date(), "yyyyMMddHHmmss");alibabaCloudFileDO.setFileName(fileName);aibabaCloudFileMapper.insert(alibabaCloudFileDO);uploadFileAliOss(exportList, fileName, alibabaCloudFileDO.getId());}@Overridepublic HttpServletResponse downLoadSouceCodeAnalysisFile(Long id, HttpServletResponse response) {AlibabaCloudFileDO alibabaCloudFileDO = aibabaCloudFileMapper.selectById(id);if (ObjectUtil.isNull(alibabaCloudFileDO)) {throw new BusinessException("文件id异常,请确认后重试");}ServletOutputStream outputStream = null;try {String fileName = URLEncoder.encode(alibabaCloudFileDO.getFileName(), "UTF-8");response.setContentType("application/x-download;charset=utf-8");response.addHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");//调用 阿里云下载File file = aliyunOssUtil.downLoadOssFile(alibabaCloudFileDO.getFileAddress(), fileName);byte[] array = FileUtils.readFileToByteArray(file);outputStream = response.getOutputStream();outputStream.write(array);outputStream.flush();} catch (IOException e) {log.error("源代码扫描文件下载失败,失败原因:", e);} finally {try {if (ObjectUtil.isNotNull(outputStream)) {outputStream.close();}} catch (IOException e) {e.printStackTrace();}}return response;}/*** @param exportList:* @param fileName:* @param id:* @description 异步上传文件到 阿里云 OSS 该业务请求量很小 所以使用了 @Async 的异步方式*/@Asyncpublic void uploadFileAliOss(List<SourceCodeAnalysisExportVO> exportList, String fileName, Long id) {File tempFile = null;AlibabaCloudFileDO alibabaCloudFileDO = new AlibabaCloudFileDO();alibabaCloudFileDO.setId(id);try {// 创建临时文件tempFile = File.createTempFile(fileName, ".xlsx");// 使用EasyExcel写入数据EasyExcel.write(tempFile, SourceCodeAnalysisExportVO.class).sheet("sheet1").doWrite(exportList);String fileUrl = aliyunOssUtil.uploadOssFile(tempFile, fileName + ".xlsx");alibabaCloudFileDO.setFileAddress(fileUrl);//更新文件生成成功alibabaCloudFileDO.setFileStatus(2);} catch (IOException e) {//文件生成失败alibabaCloudFileDO.setFileStatus(3);log.error("文件上传阿里云OSS 失败,文件导出主键id:{}", id, e);} finally {//更新aibabaCloudFileMapper.updateById(alibabaCloudFileDO);tempFile.delete();}}}
下载文件代码
完成导出后,用户可以在页面上看到下载按钮,点击下载就可以完成导出的文件下载了。
@PostMapping(value = "/download-source-code-analysis-file")@ApiOperation(httpMethod = "POST", value = "下载源代码分析文件", notes = "下载源代码分析文件")public HttpServletResponse downLoadSouceCodeAnalysisFile(@RequestParam("id") Long id, HttpServletResponse response) {return sourceCodeAnalysisService.downLoadSouceCodeAnalysisFile(id, response);}
总结:本篇重点是分享阿里云 OSS 文件上传下载功能,结合项目中的一个场景做了一个简单的异步导出,偏业务代码,简单分享,希望可以帮助到有需要的朋友。
如有不正确的地方欢迎各位指出纠正。
相关文章:
Spring Boot 集成阿里云OSS 完成文件上传下载
前言: 文件上传下载在项目开发中是一个非常常见的业务场景,在云服务上还没有兴起的时候,一般来说都会把文件单独存放到文件服务器上,随着云服务的兴起,各类云服务厂商都提供了 OSS 服务,本篇我们分享 Spri…...
使用ERA5数据绘制风向玫瑰图的简易流程
使用ERA5数据绘制风向玫瑰图的简易流程 今天需要做一个2017年-2023年的平均风向的统计,做一个风向玫瑰图,想到的还是高分辨率的ERA5land的数据(0.1分辨率,逐小时分辨率,1950年至今)。 风向,我分为了16个&…...
测试脚本并发多进程:pytest-xdist用法
参考:https://www.cnblogs.com/poloyy/p/12694861.html pytest-xdist详解: https://www.cnblogs.com/poloyy/p/14708825.html 总 https://www.cnblogs.com/poloyy/category/1690628.html...
数据可视化的Python实现
一、GDELT介绍 GDELT ( www.gdeltproject.org ) 每时每刻监控着每个国家的几乎每个角落的 100 多种语言的新闻媒体 -- 印刷的、广播的和web 形式的,识别人员、位置、组织、数量、主题、数据源、情绪、报价、图片和每秒都在推动全球社会的事件,GDELT 为全…...
【Linux系列】Linux 系统配置文件详解:`/etc/profile`、`~/.bashrc` 和 `~/.bash_profile`
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
uni-app实现小程序、H5图片轮播预览、双指缩放、双击放大、单击还原、滑动切换功能
前言 这次的标题有点长,主要是想要表述的功能点有点多; 简单做一下需求描述 产品要求在商品详情页的头部轮播图部分,可以单击预览大图,同时在预览界面可以双指放大缩小图片并且可以移动查看图片,双击放大࿰…...
游戏引擎学习第45天
仓库: https://gitee.com/mrxiao_com/2d_game 回顾 我们刚刚开始研究运动方程,展示了如何处理当人物遇到障碍物时的情况。有一种版本是角色会从障碍物上反弹,而另一版本是角色会完全停下来。这种方式感觉不太自然,因为在游戏中,…...
electron常用方法
一,,electron设置去除顶部导航栏和menu 1,electron项目 在创建BrowserWindow实例的main.js页面添加frame:false属性 2,electron-vue项目 在src/main/index.js文件下找到创建窗口的方法(createWindow)&…...
【Spark】Spark Join类型及Join实现方式
如果觉得这篇文章对您有帮助,别忘了点赞、分享或关注哦!您的一点小小支持,不仅能帮助更多人找到有价值的内容,还能鼓励我持续分享更多精彩的技术文章。感谢您的支持,让我们一起在技术的世界中不断进步! Sp…...
meta llama 大模型一个基础语言模型的集合
LLaMA 是一个基础语言模型的集合,参数范围从 7B 到 65B。我们在数万亿个 Token 上训练我们的模型,并表明可以专门使用公开可用的数据集来训练最先进的模型,而无需诉诸专有的和无法访问的数据集。特别是,LLaMA-13B 在大多数基准测试…...
JAVA爬虫获取1688关键词接口
以下是使用Java爬虫获取1688关键词接口的详细步骤和示例代码: 一、获取API接口访问权限 要使用1688关键词接口,首先需要获取API的使用权限,并了解接口规范。以下是获取API接口的详细步骤: 注册账号:在1688平台注册一…...
操作系统——内存管理
1、什么是虚拟内存?它是如何实现的?虚拟内存与物理内存之间有什么关系? 虚拟内存是操作系统提供的一种内存管理机制,它使程序认为自己拥有连续的内存空间,但实际上内存可能被分散存储在物理内存和磁盘交换空间中。 虚…...
android studio 模拟器不能联网?
模拟器路径: C:\Users\Administrator\AppData\Local\Android\Sdk\emulator\emulator.exe.关闭所有AVD设备实例 导航至: C:\Users\userName\AppData\Local\Android\Sdk\emulator查看模拟器名称 AdministratorDESKTOP-6JB1OGC MINGW64 ~/AppData/Local/…...
CTF-WEB: 目录穿越与模板注入 [第一届国城杯 Ez_Gallery ] 赛后学习笔记
step1 验证码处存在逻辑漏洞,只要不申请刷新验证码就一直有效 字典爆破得到 admin:123456 step2 /info?file../../../proc/self/cmdline获得 python/app/app.py经尝试,读取存在的目录时会返回 A server error occurred. Please contact the administrator./info?file.…...
数据结构6.4——归并排序
基本思想: 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个…...
【html 常用MIME类型列表】
本表仅列出了常用的MIME类型,完整列表参考文档。 浏览器通常使用 MIME 类型(而不是文件扩展名)来确定如何处理 URL,因此 Web 服务器在响应头中添加正确的 MIME 类型非常重要。 如果配置不正确,浏览器可能会曲解文件内容…...
Linux之vim编辑器
vi编辑器是所有Unix及linux系统下标准的编辑器,类似于Windows系统下的记事本。很多软件默认使用vi作为他们编辑的接口。vim是进阶版的vi,vim可以视为一种程序编辑器。 前言: 1.文件准备 复制 /etc/passwd文件到自己的目录下(不…...
【工具介绍】可以批量查看LableMe标注的图像文件信息~
在图像处理和计算机视觉领域,LabelMe是一个广泛使用的图像标注工具,它帮助我们对图像中的物体进行精确的标注。但是,当标注完成后,我们常常需要一个工具来批量查看这些标注信息。 今天,我要介绍的这款exe程序…...
2024年山西省第十八届职业院校技能大赛 (高职组)“信息安全管理与评估”赛项规程
2024年山西省第十八届职业院校技能大赛 (高职组)“信息安全管理与评估”赛项规程 一、赛项名称 赛项名称:信息安全管理与评估 英文名称:Information Security Management and Evaluation 赛项组别:高职教师组 赛项归属…...
STM32完全学习——STemWin的移植小插曲
一、移植编译的一些问题 新版的STemWin的库没有区别编译器,只有一些这样的文件,默认你将这些文件导入到KEIL中,然后编译就会有下面的错误。 ..\MEWIN\STemWin\Lib\STemWin_CM4_wc16.a(1): error: A1167E: Invalid line start ..\MEWIN\STe…...
Java——IO流(下)
一 (字符流扩展) 1 字符输出流 (更方便的输出字符——>取代了缓冲字符输出流——>因为他自己的节点流) (PrintWriter——>节点流——>具有自动行刷新缓冲字符输出流——>可以按行写出字符串,并且可通过println();方法实现自动换行) 在Java的IO流中…...
avue-crud 同时使用 column 与 group 的问题
场景一:在使用option 中的column 和 group 进行表单数据新增操作时,进行里面的控件操作时,点击后卡死问题,文本没问题 其它比如下拉,单选框操作,当删除 column 中的字段后, group 中的可以操作 …...
深入解析 Pytest 中的 conftest.py:测试配置与复用的利器
在 Pytest 测试框架中,conftest.py 是一个特殊的文件,用于定义测试会话的共享配置和通用功能。它是 Pytest 的核心功能之一,可以用于以下目的: 【主要功能】 1、定义共享的 Fixture (1)conftest.py 文件可…...
JAVA |日常开发中Websocket详解
JAVA |日常开发中Websocket详解 前言一、Websocket 概述1.1 定义1.2 优势 二、Websocket 协议基础2.1 握手过程2.2 消息格式2.3 数据传输方式 三、Java 中使用 Websocket3.1 Java WebSocket API(JSR - 356)3.2 第三方库(如 Tyrus&…...
Typora教程
目录 一、下载安装 二、激活 1.激活 2.解决激活提示窗口 一、下载安装 去官网下载Typora安装,我的是1.9.5版本 二、激活 1.激活 根据路径找到Typora/resources/page-dist/static/js 使用记事本打开LicenseIndex文件,如下图: 按住快捷…...
泛微E9常见API保姆级详解!!!!
前言 在泛微前端开发过程中,虽然大部分是对流程以及流程逻辑的调整,但是还是会有一些小的个性化需求是需要借助JS来实现的。 比如:对同一组数据,前后变化不一样时,需要对这组变化后的数据进行标红处理;对提…...
UniApp配置使用原子化tailwindcss
参考视频 创建项目 新建项目选择uniapp - vue版本这里我选择3 - 点击创建即可 创建完成后,如果是要编译到小程序的项目则可以先将项目运行到小程序打开了 初始化package.json 执行 npm init -y安装和配置 安装 npm i -D tailwindcss postcss autoprefixer # 安…...
02. Docker:安装和操作
目录 一、Docker的安装方式 1、实验环境准备 1.1 关闭防火墙 1.2 可以访问网络 1.3 配置yum源 2、yum安装docker 2.1 安装docker服务 2.2 配置镜像加速 2.3 启动docker服务 3、二进制安装docker 3.1 下载或上传安装包并解压 3.2 配置使用systemctl管理 3.3 配置镜像…...
【MySQL中多表查询和函数】
目录 1.多表查询 1.1 外键 1.2 链接查询 2.MySQL函数 内置函数简介 数值函数 字符串函数 时间日期函数 条件判断操作 开窗函数 1.多表查询 本质:把多个表通过主外键关联关系链接(join)合并成一个大表,在去单表查询操作…...
加速科技精彩亮相ICCAD 2024
12月11日—12日 ,中国集成电路设计业的年度盛会——ICCAD 2024在上海世博馆隆重举行。本次活动以“智慧上海,芯动世界”为主旨,汇聚了众多业界精英,共同探讨集成电路产业的未来。作为半导体测试行业领军企业,加速科技携…...
宁波网站建设优化排名/下载百度app最新版到桌面
答案是肯定的 不然这篇博客就没有存在的意义了 ——————————————下面是正文———————————————— 首先来看下以下这个代码: #include <iostream>class Base { private:int x; public:int y; };class Sub: Base { public:int a;int …...
中国空间站科幻作文1000字/整站优化网站
法一:用链表来存数据,需要查找的时候,从头遍历取数据,最简单的思路,最麻烦的代码╮(╯_╰)╭ import java.util.ArrayList;import java.util.Iterator;import java.util.List;import java.util.Scanner;//where stand…...
海外购物商城/网站推广排名优化
程序员——是一个集思维、情商、行为都异于其他传统岗位的群体。清高自傲、闷骚、会修电脑、宅、不善交际、几百年不洗的衬衫牛仔双肩包…,代表着程序员这个群体的鲜明标签。 在目前互联网发展的浪潮中,更是涌现出了以马化腾、雷军为代表的著名程序猿及成…...
西安的商城网站建设/郑州seo优化外包
一、云计算服务器与传统物理服务器有什么区别?传统物理服务器是“物理上存在的服务器”。云服务器通常被描述为“用户接处不到实体物理的服务器”,但实际上存在物理服务器。那么,两者之间的区别在于物理服务器一次引用一个服务器。对于本地服…...
连云港网站推广优化/阿里云建站费用
MCU型号: R7F0C004 编辑软件:CS for CC boot区程序地址分配:0x0000-0x1ffff app区程序地址分配: 0x2000-0xfffff App程序中,中断函数的跳转定义 section地址段的分配,因为app区起始地址处存放的是偏移后的中断向量表&…...
网站的优化什么做/什么软件可以发布广告信息
1.配置ssh keyssh-keygen -t rsa -C "注册GitHub的邮箱"Enter file in which to save the key (/c/Users/yongfengnice/.ssh/id_rsa): //提示输入key保存的文件名称,默认是用户名下的.ssh文件夹下的id_rsa文件Enter passphrase (empty for no passphrase)…...