SpringBoot从0-1集成Minio对象存储

✨重磅!盹猫的个人小站正式上线啦~诚邀各位技术大佬前来探秘!✨

这里有:

  • 硬核技术干货:编程技巧、开发经验、踩坑指南,带你解锁技术新姿势!
  • 趣味开发日常:代码背后的脑洞故事、工具测评,让技术圈不再枯燥~
  • 独家资源分享:开源项目、学习资料包,助你打怪升级快人一步!

👉 点击直达→ 盹猫猫的个人小站 👈

🌟 来逛逛吧,说不定能挖到你正在找的技术宝藏哦~

目录

[🎁 前言](#🎁 前言)

[⬇️ 下载运行minio](#⬇️ 下载运行minio)

[🌲 环境准备](#🌲 环境准备)

[🐴 代码步骤](#🐴 代码步骤)

[⚙️ 配置文件](#⚙️ 配置文件)

[⚙️ 配置类](#⚙️ 配置类)

[🔧 工具类](#🔧 工具类)

[1️⃣ 注入MinioClient](#1️⃣ 注入MinioClient)

[2️⃣ 上传图片](#2️⃣ 上传图片)

[3️⃣ 删除文件](#3️⃣ 删除文件)

[4️⃣ 获取临时文件链接](#4️⃣ 获取临时文件链接)

[5️⃣ 设置桶目录访问权限](#5️⃣ 设置桶目录访问权限)

[❓ 疑问解答](#❓ 疑问解答)

[⭐ 如何使用nginx进行代理minio配置?](#⭐ 如何使用nginx进行代理minio配置?)

[⭕ 总结](#⭕ 总结)


欢迎来到 盹猫(>^ω^<)的博客

本篇文章主要介绍了

**SpringBoot从0-1集成Minio对象存储**

❤博主广交技术好友,喜欢文章的可以关注一下❤

🎁 前言

在SpringBoot开发过程中,上传一些图片、视频资源是经常用到的功能需求,比如说头像上传,身份证信息上传,视频文件上传等。但这些上传之间存在着一些差别,比如说头像图片(一般会作为公开数据),其它用户是可以看到你的头像。而身份证图片一般是私有数据,不希望其它人可以查看你的身份证信息。

这时如果将上传的图片放到公开的容器(如:tomcat)是不合适的,那怎么解决这个问题呢?

解决方法就是**部署并集成oss对象存储系统 ,**而经常用到的就是minio对象存储服务。本篇就是记录SpringBoot如何集成minio对象存储系统,但在此之前先看下minio是什么。

🤔 什么是minio对象存储系统?

MinIO 是一款开源的、高性能的对象存储服务器,兼容 Amazon S3(Simple Storage Service)API 接口,专为海量非结构化数据(如图片、视频、日志文件、备份数据、容器镜像等)设计,可部署在私有云、公有云、边缘设备等多种环境中。

废话不多说,让我们看看如何集成吧!

Let's GO!

⬇️ 下载运行minio

当然第一步肯定是需要下载并运行minio服务,方法很简单,以Windows为例,可以点击下方的链接进行下载:

https://dl.min.io/server/minio/release/windows-amd64/minio.exe

当然,可以选择release路径下选择不同的系统环境进行下载。

下载完成后,在minio.exe所在目录通过cmd命令行运行下面的命令:

bash 复制代码
./minio.exe server ./data --console-address ":9001" --address ":8972"

--console-address ":9001" : 表示控制台运行在9001端口。

--address ":8972":表示可以通过8972进行S3服务的调用,即在SpringBoot中主要用到这个端口调用API访问。

上述端口可根据实际需要进行修改配置。

运行后可在浏览器访问本机的9001端口,出现如图界面:

默认用户名和密码均为minioadmin,登录后进行管理界面,根据需求创建一个bucket(容器桶)。

🌲 环境准备

在Pom文件中引入下述minio依赖,集成官方的SDK,这可以使我们方便的调用MinioClient类进行文件上传等操作,依赖如下:

XML 复制代码
 <dependency>
     <groupId>io.minio</groupId>
     <artifactId>minio</artifactId>
     <version>8.4.3</version>
 </dependency>

🐴 代码步骤

⚙️ 配置文件

在springboot的yml文件中添加下述依赖配置,这会在后面的配置类中使用,其中包括minio服务URL(即S3服务接口8972),公钥(登录的用户名),密钥(登录的密码),桶名称(创建的bucket名称),如下:

java 复制代码
minio:
  endpoint: minio服务url
  access-key: 公钥
  secret-key: 密钥
  bucket-name: 存储桶的名称

⚙️ 配置类

创建一个配置类,该类用于创建MinioClient,并交与SpringBoot管理,这样在后续的编码过程中就可以注入使用了,代码如下:

java 复制代码
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.MalformedURLException;

/**
 * minio配置类
 * @author nodcat
 * @version 1.0
 * @since 2025/12/20 上午9:52
 */
@Configuration
public class MinioConfig {
    @Value("${minio.endpoint}")
    private String endpoint;

    @Value("${minio.access-key}")
    private String accessKey;

    @Value("${minio.secret-key}")
    private String secretKey;

    @Bean
    public MinioClient minioClient() throws MalformedURLException {

        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
}

🔧 工具类

1️⃣ 注入MinioClient

在工具类中,需要注入自定义的MinioClient和桶名称,用于在方法中对实际的桶进行操作,代码如下:

java 复制代码
    private final MinioClient minioClient;

    @Value("${minio.bucket-name}")
    private String bucketName;

    // 构造器注入 MinioClient
    public MinioUtil(MinioClient minioClient) {
        this.minioClient = minioClient;
    }

2️⃣ 上传图片

在上传文件时,只需要设置桶名称、远程的对象名称(如果是路径+名称,则会自动创建目录)、输入流、文件类型,如这里的代码会在桶内创建一个images目录,且使用上传的文件的sha256hex作为文件名,代码如下:

java 复制代码
    /**
     * 上传文件
     * @param file 待上传的文件
     * @return 文件在 MinIO 中的存储路径
     */
    public String uploadImage(MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        String originalFilename = file.getOriginalFilename();
        // 获取文件扩展名
        String extension = FilenameUtils.getExtension(originalFilename);
        String md5;
        try (InputStream inputStream = file.getInputStream()) {
            hex256 = DigestUtils.sha256Hex(inputStream).toLowerCase();
        }
        //目录和名称
        String objectName = "images/" + hex256 + "." + extension;
        try (InputStream inputStream = file.getInputStream()) {
            minioClient.putObject(
                    PutObjectArgs.builder()
                             //设置桶名称
                            .bucket(bucketName)
                             //对象名称
                            .object(objectName)
                             //输入流
                            .stream(inputStream, file.getSize(), -1)
                             //文件类型
                            .contentType(file.getContentType())
                            .build()
            );
        }
        return objectName;
    }

上传完成后即可在控制台看到创建的目录和上传的文件,如下:

3️⃣ 删除文件

删除文件时就更简单了,直接设置好桶名称和对象名称,并调用**removeObject()**方法即可,代码如下:

java 复制代码
    /**
     * 删除文件
     * @param objectName 文件在 MinIO 中的存储路径
     */
    public void deleteFile(String objectName) throws io.minio.errors.ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        // 先判断文件是否存在
        minioClient.statObject(
                StatObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build()
        );
        // 删除文件
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        //桶名称
                        .bucket(bucketName)
                        //对象名称
                        .object(objectName)
                        .build()
        );
    }

4️⃣ 获取临时文件链接

生成临时文件链接可以实现文件的私有性访问,使用getPresignedObjectUrl方法并设置获取方式、桶名称、对象名称、超时时间,即可生成具有时效性的图片/文件的访问链接,这在存储一些用户隐私数据时很有用(比如身份证信息),代码如下:

java 复制代码
    /**
     * 获取文件临时访问链接
     * @param objectName MinIO 存储的对象名(如:images/9e107d9d372bb6826bd81d3542a419d6.jpg)
     * @param expireSeconds 链接有效期(秒),如 3600 = 1小时
     * @return 临时访问链接
     */
    public String getPreSignedUrl(String objectName, int expireSeconds) throws Exception {
        // 生成GET方法的临时签名链接
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        //可以使用GET获取
                        .method(Method.GET)
                        //桶名称设置
                        .bucket(bucketName)
                        //对象名称设置
                        .object(objectName)
                        //超时时间
                        .expiry(expireSeconds)
                        .build()
        );
    }

生成链接格式如下:

http://127.0.0.1:9000/plant-protection-platform/images/9e128ae0715b9723eddf9165ecdf658ac901ac437a20d4e5bf84e4af876c7627.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minio%2F20251222%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20251222T010843Z&X-Amz-Expires=500&X-Amz-SignedHeaders=host&X-Amz-Signature=4c36f9869623b1bac0427ea3b8ad782b70ae358975b728f28022b95c58e3d2e9

5️⃣ 设置桶目录访问权限

创建的目录默认为私有访问权限,若需要将其设定为公开访问权限可以setBucketPolicy方法对桶策略进行设置,代码如下:

java 复制代码
    /**
     * 将指定桶路径配置为「公开读权限」(匿名用户可访问所有文件)
     * @throws Exception 配置失败时抛出异常
     */
    public void setBucketPublicRead(String path) throws Exception {
        // 1. 构造桶策略 JSON:允许所有匿名用户读取桶内所有对象
        JSONObject policyJson = new JSONObject();
        policyJson.put("Version", "2012-10-17");

        // 策略声明:仅允许 GetObject(读文件),禁止 ListBucket(列文件)
        JSONObject statement = new JSONObject();
        statement.put("Effect", "Allow");
        statement.put("Principal", "*");
        statement.put("Action", "s3:GetObject");
        // 资源范围:该桶下的所有对象(/* 表示桶内所有文件)
        statement.put("Resource", "arn:aws:s3:::" + bucketName + "/"+path);

        policyJson.put("Statement", new JSONObject[]{statement});

        // 2. 应用桶策略
        minioClient.setBucketPolicy(
                SetBucketPolicyArgs.builder()
                        .bucket(bucketName)
                        .config(policyJson.toJSONString())
                        .build()
        );
        System.out.println("桶 " + bucketName+"/"+path+"已配置为公开读权限!");
    }

这里如果传入images/* ,则通过公开链接就可以直接访问某个目录,链接格式如下:

http://127.0.0.1:9000/plant-protection-platform/images/9e128ae0715b9723eddf9165ecdf658ac901ac437a20d4e5bf84e4af876c7627.jpg

❓ 疑问解答

⭐ 如何使用nginx进行代理minio配置?

使用下面的配置,即可实现nginx对对minio服务进行代理,内容如下:

java 复制代码
# API接口代理配置
    location / {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_connect_timeout 300;
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      chunked_transfer_encoding off;

      proxy_pass http://192.168.0.184:8972;
    }

    # Web界面代理配置(含静态资源修正)
    location /minio-web/ {
        rewrite ^/minio-web/(.*) /$1 break;
        proxy_pass http://192.168.0.184:9001/;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-NginX-Proxy true;
        
        # WebSocket支持配置
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # 静态资源路径修正
        sub_filter '<base href="/"/>' '<base href="/minio-web/"/>';
        sub_filter_once off;
    }

其中web管理界面可以使用/minio-web/路径进行转发,但是S3接口不能使用带路径的访问格式,必须直接用根路径进行端口映射。

⭕ 总结

可以看出,通过让SpringBoot去集成Minio即可很容易的实现文件和访问权限管理,并且Minio SDK进行了一些标准化的构造器,简化了开发流程。文章只是对一些操作代码进行举例,还有很多其它的操作等待你去探索,快去动手试试吧!

上面就是所有文章内容了,如果内容对你有帮助,麻烦留一个赞👍和收藏⭐支持一下!


如果你对区块链 内容感兴趣可以查看我的专栏:小试牛刀-区块链

感谢您的关注和收藏!!!!!!

相关推荐
疯狂的程序猴2 小时前
iOS 上架需要哪些准备,围绕证书、描述文件和上传方式等关键环节展开分析
后端
故渊ZY2 小时前
MyBatis事务原理与实战指南
java·mybatis
HTouying2 小时前
线程池【工具类】
java
深盾科技2 小时前
融合C++与Python:兼顾开发效率与运行性能
java·c++·python
我待_JAVA_如初恋2 小时前
idea创建MavenJavaWeb项目以后,包结构缺java
java·ide·intellij-idea
无限大62 小时前
为什么"API"很重要?——从封闭系统到开放生态
后端
来深圳2 小时前
leetcode 739. 每日温度
java·算法·leetcode
王中阳Go2 小时前
Golang框架封神榜!GitHub星标TOP8大比拼,选对框架少走3年弯路
后端·面试·go
CC大煊2 小时前
【java】Druid数据库连接池完整配置指南:从入门到生产环境优化
java·数据库·springboot