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,当然为了安全也可以生成访问外链
在这里插入图片描述

至此结束 ,有问题欢迎留言指出谢谢!

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

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

相关文章

【开源宝藏】Spring Trace 一种轻量级的日志追踪新方式

Spring Trace&#xff1a;一种轻量级的日志追踪新方式 一、前言 在日常开发中&#xff0c;我们常常需要在日志中标记某个请求的唯一标识&#xff08;Trace ID&#xff09;或上下文信息&#xff0c;以便快速定位问题或查看调用链路。传统做法通常会使用 MDC&#xff08;Mapped…

Web网页开发——水果忍者

1.介绍 复刻经典小游戏——水果忍者 2.预览 3.代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&…

【Flink银行反欺诈系统设计方案】6.用户画像数据与反欺诈系统的关联思路

【Flink银行反欺诈系统设计方案】6.用户画像数据与反欺诈系统的关联思路 概要1. 用户画像数据与反欺诈系统的关联思路1.1 用户画像数据内容1.2 数据赋能反欺诈的核心逻辑 2. 用户画像赋能反欺诈的3个案例2.1 案例1&#xff1a;消费习惯异常检测2.2 案例2&#xff1a;设备/地理位…

如何在unity中完整录制一段动画

在动画制作中&#xff0c;需要对接音频部门进行音效的制作。通常需要完整且无多余帧数的动画视频作为时间和帧数对帧参考&#xff0c;这时候手动录屏就会显得不够精确&#xff0c;这里分享一个插件录制方法&#xff0c;可以自定义录制起始位置&#xff0c;0帧起手完整录制。 录…

Jetson Orin 安装 onnxruntime

Jetson Orin 安装 onnxruntime onnxruntime在Jetson上安装只需注意三件事&#xff1a; 版本&#xff01; 版本&#xff01; 还是TMD版本&#xff01; 本机环境 Jectpack : 5.1.2CUDA : 11.4cuDNN &#xff1a;8.6.0 版本说明 关于onnxruntime的版本适配不同的官方有不同的…

Manus AI : Agent 元年开启.pdf

Manus AI : Agent 元年开启.pdf 是由华泰证券出品的一份调研报告&#xff0c;共计23页。报告详细介绍了Manus AI 及 Agent&#xff0c;主要包括Manus AI 的功能、优势、技术能力&#xff0c;Agent 的概念、架构、应用场景&#xff0c;以及 AI Agent 的类型和相关案例&#xff0…

【为什么会有 map、weakmap 类型?】

为什么会有 map、weakmap 类型? 传统对象的局限性催生 Map‌1. 键类型单一性‌2. 有序性与迭代支持‌3. 性能优化场景‌ 内存管理需求催生 WeakMap‌1.弱引用机制‌2. 私有数据存储‌3. 规避循环引用问题‌ 总结 传统对象的局限性催生 Map‌ 1. 键类型单一性‌ 传统对象&…

SpringSecurity认证授权完整流程

SpringSecurity认证流程&#xff1a;loadUserByUsername&#xff08;&#xff09;方法内部实现。 实现步骤&#xff1a; 构建一个自定义的service接口&#xff0c;实现SpringSecurity的UserDetailService接口。建一个service实现类&#xff0c;实现此loadUserByUsername方法。…

本地部署DeepSeek R1大数据模型知识库

DeepSeek-V3 的综合能力 DeepSeek-V3 在推理速度上相较历史模型有了大幅提升。在目前大模型主流榜单中&#xff0c;DeepSeek-V3 在开源模型中位列榜首&#xff0c;与世界上最先进OpenAI 闭源模型不分伯仲。 1、下载Ollama运行大数据库 Ollama支持 Llama 3.3, DeepSeek-R1, Phi-…

云端秘境:EC2的奇幻之旅

在一个神秘的云端世界里&#xff0c;流传着一个传说——只要掌握了 EC2&#xff08;Elastic Compute Cloud&#xff09; 的奥秘&#xff0c;就能召唤出强大的骑士军团&#xff0c;在云端之上建造属于自己的帝国。年轻的程序法师 艾伦&#xff08;Allen&#xff09;&#xff0c;…

【javaEE】多线程(基础)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

一周学会Flask3 Python Web开发-WTForms表单验证

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们可以通过WTForms表单类属性的validators属性来实现表单验证。 常用的WTForms验证器 验证器说明DataRequired(messageNo…

STM32标准库代码详解之GPIO

GPIO的初始化代码如下&#xff1a; /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟&#xff0c;使用外设必须开启/*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量 GPIO_InitStructure.GPIO_Mode GPIO_Mo…

华为欧拉系统 Tomcat 安装详解

1. 安装或确认安装 Java Tomcat 需要 Java 环境(JDK 或 JRE)才能运行。如果系统尚未安装 Java,可以使用以下命令安装 OpenJDK: # 更新软件包索引 yum update -y# 安装 OpenJDK 21(可根据需求安装其他版本,如 8、11、17 等) yum install -y java-21-openjdk java-21-op…

第六课:数据库集成:MongoDB与Mongoose技术应用

本文详细介绍了如何在Node.js应用程序中集成MongoDB数据库&#xff0c;并使用Mongoose库进行数据操作。我们将涵盖MongoDB在Ubuntu 20系统中的安装、Bash命令的CRUD操作、Mongoose数据建模&#xff08;Schema/Model&#xff09;、关联查询与聚合管道&#xff0c;以及实战案例—…

大数据学习(56)-Impala

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主哦&#x1f91…

【C#】async与await介绍

1. 实例1 1.1 代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace ConsoleApp1 {class Program{static void Main(string[] args){Method1();Method2();Console.ReadKey();}public static…

【大模型基础_毛玉仁】1.1 基于统计方法的语言模型

【大模型基础_毛玉仁】1.1 基于统计方法的语言模型 1.语言模型基础1.1 基于统计方法的语言模型1.1.1 n-grams 语言模型1.1.2 n-grams 的统计学原理 1.语言模型基础 语言是概率的。语言模型&#xff08;LanguageModels, LMs&#xff09;旨在准确预测语言符号的概率。 将按照语…

JavaScript(最后一个元素的索引就是数组的长度减 1)array.length - 1

在不同的编程语言中&#xff0c;表示数组中最后一个元素的方法略有不同&#xff0c;但基本思路都是利用数组的长度或索引来实现。 以下是一些常见编程语言中获取数组最后一个元素的方法&#xff1a; 1. JavaScript: 使用 array.length - 1 索引: 这是最常见和传统的方法。Java…

SpringCloud中使用服务名调用场景总结

一 API Gateway 在 Spring Cloud API Gateway 中&#xff0c;通过使用 lb:// 前缀可以实现基于服务名的负载均衡路由。以下是具体的配置和使用方法&#xff1a; 1. 配置服务注册与发现 确保你的服务已经注册到服务注册中心&#xff08;如 Nacos 或 Eureka&#xff09;。API …