Spring Boot集成Minio笔记
一、首先配置MinIO
1、MinIO新建Bucket,访问控制台如图
创建访问密钥(就是账号和密码)
二、集成mino添加Minio客户端依赖
1.maven构建方式在pom.xml引入jar
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.4.3</version></dependency>
2.配置Minio连接参数
Springoot配置文件yaml添加minio配置Minio连接参数:
# minio 参数配置minio:#是否启用 默认值是trueenabled: true#是否https ,#如果是true,则用的是https而不是http,默认值是falsesecure: false#文件预览地址 由于我们的MinIO服务运行在9001端口上preview: http://127.0.0.1:9001#Minio服务器地址endpoint: http://127.0.0.1:9001# 默认存储桶bucket-name: #登录账号access-key: MKBgpZsb7WoLFEUTeR8y#登录密码secret-key: VpONfVhjGtPOUd26yPrm3ZskvuPLF4QGSTMtWRLE
(endpoint, access key, secret key,bucket name)主要是就是四个个参数,其他是因为业务需要加的参数
三、编写服务类,实现文件上传、下载等方法
1.创建配置类,初始化MinioClient Bean
import io.minio.MinioClient;
import lombok.Data;
import okhttp3.OkHttpClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;@ConfigurationProperties(prefix = "oss.minio")
@Configuration
@Data
public class MinioConfig {/*** 服务地址*/private String endpoint;/*** 文件预览地址*/private String preview;/*** 存储桶名称*/private String bucketName;/*** 用户名*/private String accessKey;/*** 密码*/private String secretKey;/*** 是否https ,是:true 不是:false*/private Boolean secure;/*** 初始化客户端,获取 MinioClient*/@Beanpublic MinioClient minioClient() throws NoSuchAlgorithmException, KeyManagementException {MinioClient.Builder minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey);//是否https,如果是取消ssl认证if (secure) {final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {@Overridepublic void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}@Overridepublic void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};}}};X509TrustManager x509TrustManager = (X509TrustManager) trustAllCerts[0];final SSLContext sslContext = SSLContext.getInstance("SSL");sslContext.init(null, trustAllCerts, new SecureRandom());final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();OkHttpClient.Builder builder = new OkHttpClient.Builder();builder.sslSocketFactory(sslSocketFactory, x509TrustManager);builder.hostnameVerifier((s, sslSession) -> true);OkHttpClient okHttpClient = builder.build();minioClient.httpClient(okHttpClient).region("eu-west-1");}return minioClient.build();}}
2.文件上传接口
package priv.cl.oss.service;import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;/*** @ClassName MinioFileStorageService* @Description MinioFileStorageService* @Author cl* @Date 2025/2/22 16:40*/
public interface MinIOFileStorageService {/*** 上传图片文件** @param prefix 文件前缀* @param filename 文件名* @param inputStream 文件流* @return 文件url*/String uploadImgFile(String prefix, String filename, InputStream inputStream);/*** 上传html文件** @param prefix 文件前缀* @param filename 文件名* @param inputStream 文件流* @return 文件url*/String uploadHtmlFile(String prefix, String filename, InputStream inputStream);/*** 上传文件不分类型** @param prefix 文件前缀* @param filename 文件名* @param multipartFile 文件* @return 文件url*/String uploadFileByMultipartFile(String prefix, String filename, MultipartFile multipartFile);/*** 上传本地文件** @param prefix 文件前缀* @param objectName 对象名称* @param fileName 本地文件路径*/String uploadFile(String prefix, String objectName, String fileName);/*** 下载文件url到本地指定路径** @param fileUrl 文件url* @param templatePath 指定路径文件夹* @return path 本地文件全路径*/String downloadFile(String fileUrl, String templatePath);/*** 下载文件** @param fileUrl 文件url* @return*/byte[] downloadFile(String fileUrl);/*** 删除文件** @param fileUrl 文件url*/void deleteFile(String fileUrl);
}
3.文件上传实现类
package priv.cl.oss.service;import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import priv.cl.oss.config.MinioConfig;import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;/*** @ClassName MinIOFileStorageServiceImpl* @Description MinIOFileStorageServiceImpl* @Author cl* @Date 2025/2/22 16:45*/
@Slf4j
@Service
public class MinIOFileStorageServiceImpl implements MinIOFileStorageService {private String separator = "/";@Autowiredprivate MinioClient minioClient;@Autowiredprivate MinioConfig minioConfig;/*** @param dirPath* @param filename yyyy/mm/dd/file.jpg* @return*/public String builderFilePath(String dirPath, String filename) {StringBuilder stringBuilder = new StringBuilder(50);if (!StringUtils.isEmpty(dirPath)) {stringBuilder.append(dirPath).append(separator);}SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");String todayStr = sdf.format(new Date());stringBuilder.append(todayStr).append(separator);stringBuilder.append(filename);return stringBuilder.toString();}/*** 获取文件名* @param fileUrl* @return*/public String getFilePathByFileUrl(String fileUrl) {String filePath = fileUrl.replace(minioConfig.getEndpoint() + "/", "");int index = filePath.indexOf(separator);filePath = filePath.substring(index + 1);return filePath;}/*** 上传图片文件** @param prefix 文件前缀* @param filename 文件名* @param inputStream 文件流* @return url*/@Overridepublic String uploadImgFile(String prefix, String filename, InputStream inputStream) {String filePath = builderFilePath(prefix, filename);try {PutObjectArgs putObjectArgs = PutObjectArgs.builder().object(filePath).contentType("image/jpg").bucket(minioConfig.getBucketName()).stream(inputStream, inputStream.available(), -1).build();minioClient.putObject(putObjectArgs);StringBuilder urlPath = new StringBuilder(minioConfig.getPreview());urlPath.append(separator + minioConfig.getBucketName());urlPath.append(separator);urlPath.append(filePath);return urlPath.toString();} catch (Exception e) {log.error("minio put file error.", e);throw new RuntimeException("上传文件失败");}}/*** 上传html文件** @param prefix 文件前缀* @param filename 文件名* @param inputStream 文件流* @return url*/@Overridepublic String uploadHtmlFile(String prefix, String filename, InputStream inputStream) {String filePath = builderFilePath(prefix, filename);try {PutObjectArgs putObjectArgs = PutObjectArgs.builder().object(filePath).contentType("text/html").bucket(minioConfig.getBucketName()).stream(inputStream, inputStream.available(), -1).build();minioClient.putObject(putObjectArgs);StringBuilder urlPath = new StringBuilder(minioConfig.getEndpoint());urlPath.append(separator + minioConfig.getBucketName());urlPath.append(separator);urlPath.append(filePath);return urlPath.toString();} catch (Exception e) {log.error("minio put file error.", e);throw new RuntimeException("上传文件失败");}}/*** 上传文件不分类型** @param prefix 文件前缀* @param filename 文件名* @param multipartFile 文件流* @return url*/@Overridepublic String uploadFileByMultipartFile(String prefix, String filename, MultipartFile multipartFile) {String filePath = builderFilePath(prefix, filename);try {// 将MultipartFile转换为InputStreamInputStream inputStream = multipartFile.getInputStream();PutObjectArgs putObjectArgs = PutObjectArgs.builder().object(filePath).contentType(multipartFile.getContentType()).bucket(minioConfig.getBucketName()).stream(inputStream, multipartFile.getSize(), -1).build();minioClient.putObject(putObjectArgs);StringBuilder urlPath = new StringBuilder(minioConfig.getPreview());urlPath.append(separator + minioConfig.getBucketName());urlPath.append(separator);urlPath.append(filePath);return urlPath.toString();} catch (Exception e) {log.error("minio put file error.", e);throw new RuntimeException("上传文件失败");}}/*** 上传本地文件** @param prefix 文件前缀* @param objectName 文件名称* @param fileName 本地文件全路径*/@Overridepublic String uploadFile(String prefix, String objectName, String fileName) {String filePath = builderFilePath(prefix, objectName);try {UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).filename(fileName).build();minioClient.uploadObject(uploadObjectArgs);StringBuilder urlPath = new StringBuilder(minioConfig.getEndpoint());urlPath.append(separator + minioConfig.getBucketName());urlPath.append(separator);urlPath.append(filePath);return urlPath.toString();} catch (Exception e) {log.error("minio upload file error.", e);throw new RuntimeException("上传文件失败");}}/*** 下载文件url到本地指定文件夹** @param fileUrl 文件url* @param templatePath 指定路径文件夹* @return path 本地文件全路径*/@Overridepublic String downloadFile(String fileUrl, String templatePath) {String filePath = getFilePathByFileUrl(fileUrl);InputStream inputStream = null;String filename = filePath.substring(filePath.lastIndexOf(separator) + 1);try {inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).build());FileOutputStream outputStream = null;outputStream = new FileOutputStream(templatePath + filename);byte[] buff = new byte[100];int rc = 0;while (true) {try {if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break;} catch (IOException e) {log.error("文件read失败");e.printStackTrace();}outputStream.write(buff, 0, rc);}outputStream.close();inputStream.close();} catch (Exception e) {log.error("minio down file error. pathUrl:{}", fileUrl);throw new RuntimeException("下载文件url到本地指定文件夹失败");}return templatePath + filename;}/*** 下载文件** @param fileUrl 文件全路径* @return 文件流*/@Overridepublic byte[] downloadFile(String fileUrl) {String filePath = getFilePathByFileUrl(fileUrl);InputStream inputStream = null;try {inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).build());ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();byte[] buff = new byte[100];int rc = 0;while (true) {try {if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break;} catch (IOException e) {log.error("文件read失败");e.printStackTrace();}byteArrayOutputStream.write(buff, 0, rc);}return byteArrayOutputStream.toByteArray();} catch (Exception e) {log.error("minio down file error. pathUrl:{}", fileUrl);throw new RuntimeException("下载文件失败");}}/*** 删除文件** @param fileUrl 文件url*/@Overridepublic void deleteFile(String fileUrl) {String filePath = getFilePathByFileUrl(fileUrl);// 构建参数RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).build();try {minioClient.removeObject(removeObjectArgs);} catch (Exception e) {log.error("minio remove file error. pathUrl:{}", fileUrl);throw new RuntimeException("删除文件失败");}}
}
4.Controller调用
@RestController
@RequestMapping("/minio")
public class MinioController {@Autowiredprivate MinIOFileStorageService minIOFileStorageServiceImpl;@GetMapping("/test")public String test(){return "Hello World";}@PostMapping("/fileupload")public String fileupload(@RequestParam MultipartFile file){// 检查multipartFile是否为空if (file == null || file.isEmpty()) {return "文件为空,无法处理。";}// 上传到MinIO服务器// 这里的"common"是前缀String url = minIOFileStorageServiceImpl.uploadFileByMultipartFile("common", file.getOriginalFilename(), file);return url;}}
四、测试集成
1.postman调用
2.通过minio客户端查看
遇到问题
1.url无法查看
解决方案:
权限问题,设置成pulic,当然为了安全也可以生成访问外链
至此结束 ,有问题欢迎留言指出谢谢!
相关文章:

Spring Boot集成Minio笔记
一、首先配置MinIO 1、MinIO新建Bucket,访问控制台如图 创建访问密钥(就是账号和密码) 二、集成mino添加Minio客户端依赖 1.maven构建方式在pom.xml引入jar <dependency><groupId>io.minio</groupId><artifactId>minio</artifactI…...
linux c++11 gcc4 环境编译安装googletest/gtest v1.10
c11对应googletest/gtest 经过测试,c11对应版本是googletest v1.10.x 编译安装 编译环境 sudo apt-get update sudo apt-get install -y build-essential cmake下载或git clone代码 git clone https://github.com/google/googletest.git cd googletest git che…...

20250306-笔记-精读class CVRPEnv:step(self, selected)
文章目录 前言一、时间步小于 41.1 控制时间步的递增1.2 判断是否在配送中心1.3 特定时间步的操作1.4更新1.4.1 更新当前节点和已选择节点列表1.4.2 更新需求和负载1.4.3 更新访问标记1.4.4 更新负无穷掩码1.4.5 更新步骤状态,将更新后的状态同步到 self.step_state…...
文档进行embedding,Faiss向量检索
这里采用Langchain的HuggingFaceEmbeddings 参照博主,改了一些东西,因为Langchain0.3在0.2的基础上进行了一定的修改 from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings …...

一周学会Flask3 Python Web开发-在模板中渲染WTForms表单视图函数里获取表单数据
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 为了能够在模板中渲染表单,我们需要把表单类实例传入模板。首先在视图函数里实例化表单类LoginForm,然…...

Android AudioFlinger(五)—— 揭开AudioMixer面纱
前言: 在 Android 音频系统中,AudioMixer 是音频框架中一个关键的组件,用于处理多路音频流的混音操作。它主要存在于音频回放路径中,是 AudioFlinger 服务的一部分。 上一节我们讲threadloop的时候,提到了一个函数pr…...
分类学习(加入半监督学习)
#随机种子固定,随机结果也固定 def seed_everything(seed):torch.manual_seed(seed)torch.cuda.manual_seed(seed)torch.cuda.manual_seed_all(seed)torch.backends.cudnn.benchmark Falsetorch.backends.cudnn.deterministic Truerandom.seed(seed)np.random.see…...
Serilog: 强大的 .NET 日志库
Serilog 是一个功能强大的日志记录库,专为 .NET 平台设计。它提供了丰富的 API 和可插拔的输出器及格式化器,使得开发者能够轻松定制和扩展日志记录功能。在本文中,我们将探索 Serilog 的基础知识、API 使用、配置和一些常见的示例。 1. 日志…...

Matlab——添加坐标轴虚线网格的方法
第一步:在显示绘制图的窗口,点击左上角 “编辑”,然后选“坐标区属性” 第二步:点 “网格”,可以看到添加网格的方框了...
π0及π0_fast的源码解析——一个模型控制7种机械臂:对开源VLA sota之π0源码的全面分析,含我司微调π0的部分实践
前言 ChatGPT出来后的两年多,也是我疯狂写博的两年多(年初deepseek更引爆了下),比如从创业起步时的15年到后来22年之间 每年2-6篇的,干到了23年30篇、24年65篇、25年前两月18篇,成了我在大模型和具身的原始技术积累 如今一转眼已…...

TCP7680端口是什么服务
WAF上看到有好多tcp7680端口的访问信息 于是上网搜索了一下,确认TCP7680端口是Windows系统更新“传递优化”功能的服务端口,个人理解应该是Windows利用这个TCP7680端口,直接从内网已经具备更新包的主机上共享下载该升级包,无需从微…...
服务器python项目部署
角色:root, 其他用户应该也可以 1. 安装python3环境 #如果是新机器,尽量执行,避免未知报错 yum -y update python -v yum install python3 python3 -v2. 使用virtualenvwrapper 创建虚拟环境,并使用workon切换不同的虚拟环境 # 安装virtua…...

Hive-优化(语法优化篇)
列裁剪与分区裁剪 在生产环境中,会面临列很多或者数据量很大时,如果使用select * 或者不指定分区进行全列或者全表扫描时效率很低。Hive在读取数据时,可以只读取查询中所需要的列,忽视其他的列,这样做可以节省读取开销…...

C语言100天练习题【记录本】
C语言经典100题(手把手 编程) 可以在哔哩哔哩找到(url:C语言经典100题(手把手 编程)_哔哩哔哩_bilibili) 已解决的天数:一,二,五,六,八…...

记录排查服务器CPU负载过高
1.top 命令查看cpu占比过高的进程id 这里是 6 2. 查看进程中占用CPU过高的线程 id 这里是9 top -H -p 6 ps -mp 6 -o THREAD,tid,time 使用jstack 工具 产看进程的日志 需要线程id转换成16进制 jstack 6 | grep “0x9” 4.jstack 6 可以看进程的详细日志 查看日志发现是 垃圾回…...
Spring Boot 项目中 Redis 常见问题及解决方案
目录 缓存穿透缓存雪崩缓存击穿Redis 连接池耗尽Redis 序列化问题总结 1. 缓存穿透 问题描述 缓存穿透是指查询一个不存在的数据,由于缓存中没有该数据,请求会直接打到数据库上,导致数据库压力过大。 解决方案 缓存空值:即使…...

基于Spring Boot的校园失物招领系统的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...

10 【HarmonyOS NEXT】 仿uv-ui组件开发之Avatar头像组件开发教程(一)
温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! 目录 第一篇:Avatar 组件基础概念与设计1. 组件概述2. 接口设计2.1 形状类型定义2.2 尺寸类型定义2.3 组件属性接口 3. 设计原则4. 使用…...
OpenHarmony 5.0.0 Release
OpenHarmony 5.0.0 Release 版本概述 OpenHarmony 5.0.0 Release版本标准系统能力持续完善。相比OpenHarmony 5.0 Beta1,Release版本做出了如下特性新增或增强: 应用框架新增更多生命周期管理能力、提供子进程相关能力,可以对应用运行时的…...

RSA的理解运用与Pycharm组装Cryptodome库
1、RSA的来源 RSA通常指基于RSA算法的密码系统,令我没想到的是,其名字的来源竟然不是某个含有特别意义的单词缩写而成(比如PHP:Hypertext Preprocessor(超文本预处理器)),而是由1977年提出该算法的三个歪果…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...

【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...