如何在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…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
