如何在springboot项目中使用minio上传下载删除文件
引入maven依赖
<!-- minio -->
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.2</version>
</dependency>
申请 bucket | access_key | secret_key
项目中配置相关参数
minio:# access_keyaccessKey: xxxxxx# secret_keysecretKey: xxxxxx# bucketbucketName: bucket1# 内网地址endpoint: http://127.0.0.1:9000# 外网地址website: https://xxx.xxx.cn:9000# 自定义文件大小限制 注:要与spring.servlet.multipart.max-file-size | max-request-size 区分开maxFileSize:img: 10video: 30
endpoint | website | maxFileSize 可根据项目需要增删,后面不再赘述。
Minio 配置信息
/*** Minio 配置信息** @author ruoyi*/
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig
{/*** 用户名*/private String accessKey;/*** 密码*/private String secretKey;/*** 存储桶名称*/private String bucketName;/*** 服务地址*/private String endpoint;/*** 公网*/private String webSite;/*** 文件大小限制*/private MediaMaxFileSize maxFileSize;public static class MediaMaxFileSize{private Long img;private Long video;public Long getImg() {return img;}public void setImg(Long img) {this.img = img;}public Long getVideo() {return video;}public void setVideo(Long video) {this.video = video;}}public String getWebSite() {return webSite;}public void setWebSite(String webSite) {this.webSite = webSite;}public MediaMaxFileSize getMaxFileSize() {return maxFileSize;}public void setMaxFileSize(MediaMaxFileSize maxFileSize) {this.maxFileSize = maxFileSize;}public String getAccessKey() {return accessKey;}public void setAccessKey(String accessKey) {this.accessKey = accessKey;}public String getSecretKey() {return secretKey;}public void setSecretKey(String secretKey) {this.secretKey = secretKey;}public String getBucketName() {return bucketName;}public void setBucketName(String bucketName) {this.bucketName = bucketName;}public String getEndpoint() {return endpoint;}public void setEndpoint(String endpoint) {this.endpoint = endpoint;}@Beanpublic MinioClient getMinioClient() {return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();}
}
/*** 文件对象实体类*/
public class MinioFile implements Serializable {// 文件服务器文件所属组private String bucketName;// 不带文件组的文件URLprivate String path;// 带文件组的文件URLprivate String fullPath;// 站点信息private String webSite;// 带站点的文件URLprivate String webUrl;// 原始文件名private String fileName;// 内网廉价而private String intranetWebSite;// 内网地址private String intranetWebUrl;// 其他参数private Map<String, Object> params = new HashMap<>();public String getFullPath() {return fullPath;}public void setFullPath(String fullPath) {this.fullPath = fullPath;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public String getWebSite() {return webSite;}public void setWebSite(String webSite) {this.webSite = webSite;}public String getWebUrl() {return webUrl;}public void setWebUrl(String webUrl) {this.webUrl = webUrl;}public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}public String getIntranetWebUrl() {return intranetWebUrl;}public void setIntranetWebUrl(String intranetWebUrl) {this.intranetWebUrl = intranetWebUrl;}public String getIntranetWebSite() {return intranetWebSite;}public void setIntranetWebSite(String intranetWebSite) {this.intranetWebSite = intranetWebSite;}public String getBucketName() {return bucketName;}public void setBucketName(String bucketName) {this.bucketName = bucketName;}public Map<String, Object> getParams() {if (params == null) {params = new HashMap<>();}return params;}public void setParams(Map<String, Object> params) {this.params = params;}public Object getParam(String key) {if (params == null) {params = new HashMap<>();return null;}return params.get(key);}public void putParam(String key, Object value) {if (params == null) {params = new HashMap<>();}params.put(key, value);}}
文件上传下载删除工具类封装
项目基于RuoYi开源框架搭建,因此此处工具类引入开源框架中一些内置工具类
import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.common.utils.uuid.Seq;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.http.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;
import java.util.Date;/*** Minio 文件存储工具类* * @author ruoyi*/
@Component
public class MinioUtil
{private static Logger log = LoggerFactory.getLogger(MinioUtil.class);/*** minio实例*/private static MinioClient minioClient;/*** minio配置类*/private static MinioConfig minioConfig;@Autowiredpublic void setMinioUtil(MinioClient minioClient, MinioConfig minioConfig){MinioUtil.minioClient = minioClient;MinioUtil.minioConfig = minioConfig;}public MinioFile uploadFile(MultipartFile file, String fileType, String filePurpose) throws InvalidExtensionException, IOException {if("01".equals(fileType)){FileUploadUtils.assertAllowed(file, MimeTypeUtils.IMAGE_EXTENSION_10001, minioConfig.getMaxFileSize().getImg() * 1024 * 1024);} else if ("02".equals(fileType)) {FileUploadUtils.assertAllowed(file, MimeTypeUtils.VIDEO_EXTENSION_10002, minioConfig.getMaxFileSize().getVideo() * 1024 * 1024);}// 年月String yyyyMM = DateUtils.parseDateToStr("yyyyMM", new Date());// 文件名 moduleName/业务类型/文件类型/年月/Seq随机字符/文件后缀String fileName = StringUtils.format("{}/{}/{}/{}/{}.{}","moduleName", getFilePurpose(filePurpose)// 使用用途, getFileType(fileType)//文件类型, yyyyMM, Seq.getId(), FileUploadUtils.getExtension(file));return uploadFile(file, fileName);}private MinioFile uploadFile(MultipartFile file, String fileName) throws IOException {String webUrl = uploadFile(minioConfig.getBucketName(), fileName, file);MinioFile minioFile = new MinioFile();minioFile.setBucketName(minioConfig.getBucketName());minioFile.setPath(fileName);minioFile.setFullPath(StringUtils.format("{}/{}",minioConfig.getBucketName(),fileName));minioFile.setWebSite(minioConfig.getWebSite());minioFile.setWebUrl(webUrl.replace(minioConfig.getEndpoint(),minioConfig.getWebSite()));minioFile.setFileName(file.getOriginalFilename());minioFile.setIntranetWebSite(minioConfig.getEndpoint());minioFile.setIntranetWebUrl(webUrl);return minioFile;}/*** 上传文件* * @param bucketName 桶名称* @param fileName* @throws IOException*/private String uploadFile(String bucketName, String fileName, MultipartFile multipartFile) throws IOException{String url = "";try (InputStream inputStream = multipartFile.getInputStream()){minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(inputStream, multipartFile.getSize(), -1).contentType(multipartFile.getContentType()).build());url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).method(Method.GET).build());url = url.substring(0, url.indexOf('?'));return ServletUtils.urlDecode(url);}catch (Exception e){throw new IOException(e.getMessage(), e);}}/*** 删除文件* @param fileName*/public void removeFile(String fileName){try{minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).build());}catch (Exception e){e.printStackTrace();log.error("MinioUtil-uploadMinio-error", e);}}/*** 文件类型 可自定义* @param fileType* @return*/private String getFileType(String fileType){String fileTypeName = null;switch (fileType){case "01":fileTypeName = "image";break;case "02":fileTypeName = "video";break;default:fileTypeName = "undefined";}return fileTypeName;}/*** 获取文件使用用途 可自定义* @param filePurpose* @return*/private String getFilePurpose(String filePurpose){String filePurposeType = null;switch (filePurpose){case "01":filePurposeType = "banner";break;default:filePurposeType = "undefined";}return filePurposeType;}}
MimeTypeUtils.IMAGE_EXTENSION_10001 和 MimeTypeUtils.VIDEO_EXTENSION_10002为在原框架工具类上新增自定义文件后缀
另根据业务需要,对框架FileUploadUtils中的assertAllowed进行方法重载
/*** 文件大小校验** @param file 上传的文件* @return* @throws FileSizeLimitExceededException 如果超出最大大小* @throws InvalidExtensionException*/public static final void assertAllowed(MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, InvalidExtensionException{assertAllowed(file, allowedExtension, DEFAULT_MAX_SIZE);}/*** 文件大小校验** @param file 上传的文件* @param maxSize 最大限制* @return* @throws FileSizeLimitExceededException 如果超出最大大小* @throws InvalidExtensionException*/public static final void assertAllowed(MultipartFile file, String[] allowedExtension, long maxSize)throws FileSizeLimitExceededException, InvalidExtensionException{long size = file.getSize();if (size > maxSize){throw new FileSizeLimitExceededException(maxSize / 1024 / 1024);}String fileName = file.getOriginalFilename();String extension = getExtension(file);if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)){if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION){throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION){throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION){throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION){throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION_10001){throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION_10002){throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,fileName);}else{throw new InvalidExtensionException(allowedExtension, extension, fileName);}}}
相关文章:
如何在springboot项目中使用minio上传下载删除文件
引入maven依赖 <!-- minio --> <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.2</version> </dependency>申请 bucket | access_key | secret_key 项目中配置相关参数 mini…...

SSM个性化旅游管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目
一、源码特点 SSM 个性化旅游管理系统是一套完善的信息系统,结合springMVC框架完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码和数据库 ,系统主要采用B…...
4-Docker命令之docker version
1.docker version介绍 docker version命令是用于查看docker容器的版本信息 2.docker version用法 docker version [参数] [root@centos79 ~]# docker version --helpUsage: docker version [OPTIONS]Show the Docker version informationOptions:-f, --format string Fo…...

Redis高并发缓存架构
前言: 针对缓存我们并不陌生,而今天所讲的是使用redis作为缓存工具进行缓存数据。redis缓存是将数据保存在内存中的,而内存的珍贵性是不可否认的。所以在缓存之前,我们需要明确缓存的对象,是否有必要缓存,怎…...
谨防利用Redis未授权访问漏洞入侵服务器
说明: Redis是一个开源的,由C语言编写的高性能NoSQL数据库,因其高性能、可扩展、兼容性强,被各大小互联网公司或个人作为内存型存储组件使用。 但是其中有小部分公司或个人开发者,为了方便调试或忽略了安全风险&#…...
关于一些bug的解决1、el-input的输入无效2、搜索之后发现数据不对3、el多选框、单选框点击无用4、
el-input输入无效 原来的代码是 var test null 但是我发现不能输入任何值 反倒修改test的初始值为123是可以的 于是我确定绑定没问题 就是修改的问题 于是改成 var test ref() v-model绑定的值改成test.value就可以了 因为ref是相应式的 可以通过输入…...

使用 JavaScript 进行 API 测试的综合教程
说明 API 测试是软件测试的一种形式,涉及直接测试 API 并作为集成测试的一部分,以确定它们是否满足功能、可靠性、性能和安全性的预期。 先决条件: JavaScript 基础知识。Node.js 安装在您的计算机上。如果没有,请在此处下载。npm…...

Vue 2.0源码分析-Virtual DOM
Virtual DOM 这个概念相信大部分人都不会陌生,它产生的前提是浏览器中的 DOM 是很“昂贵"的,为了更直观的感受,我们可以简单的把一个简单的 div 元素的属性都打印出来,如图所示: 可以看到,真正的 DOM …...
(HAL库版)freeRTOS移植STMF103
正点原子关于freeRTOS的教程是比较好的,可惜移植的是标准库,但是我学的是Hal库,因为开发速度更快,从最后那个修改SYSTEM文件夹的地方开始替换为下面的内容就可以了 5.修改Systick中断、SVC中断、PendSV中断 将SVC中断、P…...
vue2-axios
下载axios 开发版本:axios.js 生产版本:axios.min.js 搭建服务器:json-server npm i -g json-serverjson-server --watch db.json(启动服务并读取文件,db.json文件目录下启动) json-server --watch db.j…...

创建maven的web项目
(一)创建maven的web项目 Step1、创建一个普通的maven项目 (1)新建一个empty project,命名为SSM2。 点击项目名,右键new,选择Module,左侧选择“Maven archetype”,可以给…...
使用uniapp开发系统懒加载图片效果
1、创建一个Vue组件 在uniapp项目中,我们可以创建一个独立的Vue组件来实现懒加载图片效果。打开uniapp项目,进入components文件夹,创建一个名为"LazeImage"的组件。 2、编写组件模板 在"LazeImage"组件中,…...

导入PIL时报错
在导入PIL时,报以下错误: 查找原因 参考博客 Could not find a version that satisfies the requirement PIL (from versions: ) No matching distributi-CSDN博客,按照wheel后,安装PIL时,报如下的错误。 查找说是python版本与wheel文件版本不同,确认本机python版本 …...

MyBatis Generator 插件 详解自动生成代码
MyBatis Generator(MBG)是MyBatis和iBATIS的代码生成器。可以生成简单CRUD操作的XML配置文件、Mapper文件(DAO接口)、实体类。实际开发中能够有效减少程序员的工作量,甚至不用程序员手动写sql。 它将为所有版本的MyBatis以及版本2.2.0之后的i…...
SkyWalking全景解析:从原理到实现的分布式追踪之旅
🎏:你只管努力,剩下的交给时间 🏠 :小破站 SkyWalking全景解析:从原理到实现的分布式追踪之旅 前言第一:SkyWalking简介第二:实现原理概览第三:主键与架构第四࿱…...

新手如何买卖可转债,可转债投资基础入门
一、教程描述 什么是可转债?可转债是可转换债券的二次简称,原始全称是可转换公司债券,这是一种可以在特定时间、按特定条件,转换为普通股票的特殊企业债券,可转换债券兼具债权和股权的特征,其英文为conver…...
研习代码 day39 | 动态规划——完全背包的应用
一、爬楼梯(进阶版) 1.1 题目 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬至多m (1 < m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数。 输入描述 输入共一…...
Rust语言入门教程(五) - 流控制语句
if 表达式 在Rust中, if语句的判断条件不需要用( )括起来, 它会认为所有在if 和 {之间的表达式就是判断条件,例如: if num 5 {msg "five"; }判断条件的表达式必须返回一个bool型的值, 因为Rust是一个不喜…...
字符串:leetcode1410. HTML 实体解析器
1410. HTML 实体解析器 「HTML 实体解析器」 是一种特殊的解析器,它将 HTML 代码作为输入,并用字符本身替换掉所有这些特殊的字符实体。 HTML 里这些特殊字符和它们对应的字符实体包括: 双引号:字符实体为 " ÿ…...

springboot+vue项目如何集成onlyoffice开源文档组件
一、onlyoffice是什么 ONLYOFFICE 是一个开源的办公套件,适合多人在线协作。由总部位于总部在拉脱维亚的 IT 公司Acensio System SIA 开发。它提供在线协作文档编辑器(包括文档、电子表格、演示文稿和表单),适用于 Windows、Linu…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...