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:
        #是否启用 默认值是true
        enabled: true
        #是否https ,#如果是true,则用的是https而不是http,默认值是false
        secure: 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
     */
    @Bean
    public 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() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
                        }

                        @Override
                        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
                        }

                        @Override
                        public 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 = "/";

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private 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
     */
    @Override
    public 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
     */
    @Override
    public 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
     */
    @Override
    public String uploadFileByMultipartFile(String prefix, String filename, MultipartFile multipartFile) {

        String filePath = builderFilePath(prefix, filename);
        try {
            // 将MultipartFile转换为InputStream
            InputStream 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   本地文件全路径
     */
    @Override
    public 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 本地文件全路径
     */
    @Override
    public 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 文件流
     */
    @Override
    public 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
     */
    @Override
    public 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 {

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

github进不去,一直显示错误

1、进入网址Dns检测|Dns查询 - 站长工具 2、复制检测出来的任意一个ip 3、打开电脑的文件夹&#xff1a;C:\Windows\System32\drivers\etc 下的hosts文件下复制这个ip地址 20.205.243.166 4、winr 打开cmd&#xff0c;输入ipconfig/flushdns ipconfig/flushdns出现这个就可以…

【商城实战(2)】商城架构设计:从底层逻辑到技术实现

【商城实战】专栏重磅来袭&#xff01;这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建&#xff0c;运用 uniapp、Element Plus、SpringBoot 搭建商城框架&#xff0c;到用户、商品、订单等核心模块开发&#xff0c;再到性能优化、安全加固、多端适配&#xf…

BKA-CNN基于黑翅鸢算法优化卷积神经网络的数据多特征分类预测Matlab

BKA-CNN基于黑翅鸢算法优化卷积神经网络的数据多特征分类预测Matlab 目录 BKA-CNN基于黑翅鸢算法优化卷积神经网络的数据多特征分类预测Matlab分类效果基本介绍BKA-CNN基于黑翅鸢算法优化卷积神经网络的数据多特征分类预测一、引言1.1、研究背景和意义1.2、研究现状1.3、研究目…

Windows下使用ShiftMediaProject方法编译FFmpeg

Windows SDK 8.1版本不支持dxva vp9! 需要10.0.17134.0&#xff01;或者把config编译选项去掉 1.下载源码 https://github.com/ShiftMediaProject 2.创建ShiftMediaProject文件夹 把下载好的源码放入source 3.进入SMP执行 project_get_dependencies.bat 自动下载ffmepg依赖项…

C++ Primer 动态数组

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

第四十一:Axios 模型的 get ,post请求

Axios 的 get 请求方式 9.双向数据绑定 v-model - 邓瑞编程 Axios 的 post 请求方式&#xff1a;

神经网络:AI的网络神经

神经网络&#xff08;Neural Networks&#xff09;是深度学习的基础&#xff0c;是一种模仿生物神经系统结构和功能的计算模型。它由大量相互连接的节点&#xff08;称为神经元&#xff09;组成&#xff0c;能够通过学习数据中的模式来完成各种任务&#xff0c;如图像分类、语音…

20250304在Ubuntu20.04的GUI下格式化exFAT格式的TF卡为ext4格式

20250304在Ubuntu20.04的GUI下格式化exFAT格式的TF卡为ext4格式 2025/3/4 16:47 缘起&#xff1a;128GB的TF卡&#xff0c;只能格式化为NTFS/exFAT/ext4。 在飞凌的OK3588-C下&#xff0c;NTFS格式只读。 exFAT需要改内核来支持。 现在只剩下ext4了。 linux R4默认不支持exFAT…

FPGA之硬件设计笔记-持续更新中

目录 1、说在前面2、FPGA硬件设计总计说明3、 原理图详解 - ARITX - 7 系列3.1 顶层框图介绍3.2 FPGA 电源sheet介绍&#xff1a;3.2.1 bank 14 和 bank 15的供电3.2.2 bank 0的供电3.2.3 Bank34 35 的供电 3.3 核电压和RAM电压以及辅助电压 4 原理图详解-- Ultrascale ARTIX4.…

【弹性计算】弹性裸金属服务器和神龙虚拟化(一):功能特点

《弹性裸金属服务器》系列&#xff0c;共包含以下文章&#xff1a; 弹性裸金属服务器和神龙虚拟化&#xff08;一&#xff09;&#xff1a;功能特点弹性裸金属服务器和神龙虚拟化&#xff08;二&#xff09;&#xff1a;适用场景弹性裸金属服务器和神龙虚拟化&#xff08;三&a…

【Azure 架构师学习笔记】- Azure Databricks (15) --Delta Lake 和Data Lake

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (14) – 搭建Medallion Architecture part 2 前言 ADB 除了UC 这个概念之外&#xff0c;前面【Azure 架构师学习笔记】- Azure Databricks (1…

字节跳动发布 Trae AI IDE!支持 DeepSeek R1 V3,AI 编程新时代来了!

3 月 3 日&#xff0c;字节跳动重磅发布国内首款 AI 原生集成开发环境&#xff08;AI IDE&#xff09;——Trae 国内版&#xff01; Trae 不只是一个传统的 IDE&#xff0c;它深度融合 AI&#xff0c;搭载 doubao-1.5-pro 大模型&#xff0c;同时支持DeepSeek R1 & V3&…

大模型——CogView4:生成中英双语高清图片的开源文生图模型综合介绍

CogView4:生成中英双语高清图片的开源文生图模型综合介绍 CogView4 是由清华大学 KEG 实验室(THUDM)开发的一款开源文生图模型,专注于将文本描述转化为高质量图像。它支持中英双语提示词输入,尤其擅长理解中文提示并生成带有汉字的图像,非常适合广告设计、短视频创作等场…

AI大模型爆火背后,C++ 如何助力 AI 开发大显身手?

目录 ​编辑 一、本篇背景&#xff1a; 二、C 语言的起源与发展历程&#xff1a; 2.1 起源背景&#xff1a; 2.2 发展阶段&#xff1a; 三、C 的基础特性及优势&#xff1a; 3.1 高效性能&#xff1a; 3.2 底层控制能力&#xff1a; 3.3 面向对象编程&#xff1a; 3.…

深度学习R8周:RNN实现阿尔兹海默症(pytorch)

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 数据集包含2149名患者的广泛健康信息&#xff0c;每名患者的ID范围从4751到6900不等。该数据集包括人口统计详细信息、生活方式因素、病史、临床测量、认知和功…

【笔记ing】python

1 Python基础概念及环境搭建 1.1 python简介及发展史 之父Guido van Rossum。ABC语言的替代品。Python提供了高效的数据结构&#xff0c;还能简单有效地面向对象编程。Python语法和动态类型&#xff0c;以及解释性语言的本质&#xff0c;使之成为多数平台上写脚本和快速开发应…

IDEA 接入 Deepseek

在本篇文章中&#xff0c;我们将详细介绍如何在 JetBrains IDEA 中使用 Continue 插件接入 DeepSeek&#xff0c;让你的 AI 编程助手更智能&#xff0c;提高开发效率。 一、前置准备 在开始之前&#xff0c;请确保你已经具备以下条件&#xff1a; 安装了 JetBrains IDEA&…

【leetcode hot 100 189】轮转数组

错误解法一&#xff1a;申请一个数组&#xff0c;第i个数放在新数组的ik或ik-nums.length上 class Solution {public void rotate(int[] nums, int k) {int[] resultsnew int[nums.length];for(int i0; i<nums.length; i){if(ik<nums.length){results[ik] nums[i];}els…

Express MVC

1. 安装依赖 npm init -y npm install express npm install --save-dev typescript ts-node ejs types/node types/express tsc --init 2. 项目目录结构如下&#xff0c;没有的手动创建 /my-app/src/modelsuser.ts/viewsindex.ejsuserList.ejs/controllersuserController.ts…

AI数据分析:deepseek生成SQL

在当今数据驱动的时代&#xff0c;数据分析已成为企业和个人决策的重要工具。随着人工智能技术的快速发展&#xff0c;AI 驱动的数据分析工具正在改变我们处理和分析数据的方式。本文将着重介绍如何使用 DeepSeek 进行自动补全SQL 查询语句。 我们都知道&#xff0c;SQL 查询语…