SpringBoot整合minio服务(超详细)

news2025/1/24 7:06:48

一、使用docker部署minio

1、拉取镜像

docker pull minio/minio

2、创建目录

mkdir -p /home/minio/config
mkdir -p /home/minio/data

3、创建Minio容器并运行

docker run -p 9000:9000 -p 9090:9090 \
     --net=host \
     --name minio \
     -d --restart=always \
     -e "MINIO_ACCESS_KEY=minioadmin" \
     -e "MINIO_SECRET_KEY=minioadmin" \
     -v /home/minio/data:/data \
     -v /home/minio/config:/root/.minio \
     minio/minio server \
     /data --console-address ":9090" -address ":9000"

4、登录minio控制台

 5、创建buckets存储桶测试 

创建一个名为public的存储桶(名字可自定义),上传文件。

通过http://ip:9000/存储桶名/文件名访问文件

若出现:

可以将存储桶的访问权限设置为public.

二、SpringBoot整合minio

1、创建minio-demo项目

2、引入pom依赖

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>7.0.2</version>
</dependency>

3、编写配置文件

在application.yml文件中编写相关配置。

server:
  port: 8081
spring:
  # 配置文件上传大小限制
  servlet:
    multipart:
      max-file-size: 200MB
      max-request-size: 200MB
minio:
  host: http://127.0.0.1:9000
  url: ${minio.host}/${minio.bucket}/
  access-key: minioadmin
  secret-key: minioadmin
  bucket: public

4、编写MinioConfig配置类

import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import io.minio.Result;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;


@Component
public class MinioConfig implements InitializingBean {

    @Value(value = "${minio.bucket}")
    private String bucket;

    @Value(value = "${minio.host}")
    private String host;

    @Value(value = "${minio.url}")
    private String url;

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

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

    private MinioClient minioClient;


    @Override
    public void afterPropertiesSet()
            throws Exception {
        Assert.hasText(url, "Minio url 为空");
        Assert.hasText(accessKey, "Minio accessKey为空");
        Assert.hasText(secretKey, "Minio secretKey为空");
        this.minioClient = new MinioClient(this.host, this.accessKey, this.secretKey);
    }

    /**
     * 上传
     *
     * @param multipartFile
     * @return
     * @throws Exception
     */
    public String putObject(MultipartFile multipartFile) throws Exception {
        // bucket 不存在,创建
        if (!minioClient.bucketExists(this.bucket)) {
            minioClient.makeBucket(this.bucket);
        }
        try (InputStream inputStream = multipartFile.getInputStream()) {
            // 上传文件的名称
            String fileName = multipartFile.getOriginalFilename();

            // PutObjectOptions,上传配置(文件大小,内存中文件分片大小)
            PutObjectOptions putObjectOptions =
                    new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);
            // 文件的ContentType
            putObjectOptions.setContentType(multipartFile.getContentType());
            minioClient.putObject(this.bucket, fileName, inputStream, putObjectOptions);
            // 返回访问路径
            return this.url + UriUtils.encode(fileName, StandardCharsets.UTF_8);
        }
    }

    /**
     * 列出所有存储桶名称
     *
     * @return
     * @throws Exception
     */
    public List<String> listBucketNames()
            throws Exception {
        List<Bucket> bucketList = listBuckets();
        List<String> bucketListName = new ArrayList<>();
        for (Bucket bucket : bucketList) {
            bucketListName.add(bucket.name());
        }
        return bucketListName;
    }

    /**
     * 查看所有桶
     *
     * @return
     * @throws Exception
     */
    public List<Bucket> listBuckets()
            throws Exception {
        return minioClient.listBuckets();
    }

    /**
     * 检查存储桶是否存在
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public boolean bucketExists(String bucketName) throws Exception {
        boolean flag = minioClient.bucketExists(bucketName);
        if (flag) {
            return true;
        }
        return false;
    }

    /**
     * 创建存储桶
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public boolean makeBucket(String bucketName)
            throws Exception {
        boolean flag = bucketExists(bucketName);
        if (!flag) {
            minioClient.makeBucket(bucketName);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 删除桶
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public boolean removeBucket(String bucketName)
            throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                // 有对象文件,则删除失败
                if (item.size() > 0) {
                    return false;
                }
            }
            // 删除存储桶,注意,只有存储桶为空时才能删除成功。
            minioClient.removeBucket(bucketName);
            flag = bucketExists(bucketName);
            if (!flag) {
                return true;
            }

        }
        return false;
    }

    /**
     * 列出存储桶中的所有对象
     *
     * @param bucketName 存储桶名称
     * @return
     * @throws Exception
     */
    public Iterable<Result<Item>> listObjects(String bucketName) throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            return minioClient.listObjects(bucketName);
        }
        return null;
    }

    /**
     * 列出存储桶中的所有对象名称
     *
     * @param bucketName 存储桶名称
     * @return
     * @throws Exception
     */
    public List<String> listObjectNames(String bucketName) throws Exception {
        List<String> listObjectNames = new ArrayList<>();
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                listObjectNames.add(item.objectName());
            }
        }
        return listObjectNames;
    }

    /**
     * 删除一个对象
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @throws Exception
     */
    public boolean removeObject(String bucketName, String objectName) throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            List<String> objectList = listObjectNames(bucketName);
            for (String s : objectList) {
                if(s.equals(objectName)){
                    minioClient.removeObject(bucketName, objectName);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 文件访问路径
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @return
     * @throws Exception
     */
    public String getObjectUrl(String bucketName, String objectName) throws Exception {
        boolean flag = bucketExists(bucketName);
        String url = "";
        if (flag) {
            url = minioClient.getObjectUrl(bucketName, objectName);
        }
        return url;
    }

}

5、编写MinioController类

import com.minio.demo.config.MinioConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;

@RestController
@CrossOrigin
@RequestMapping("/test")
public class MinioController {

    @Autowired
    MinioConfig minioConfig;

    // 上传
    @PostMapping("/upload")
    public Object upload(@RequestParam("file") MultipartFile multipartFile) throws Exception {
        return this.minioConfig.putObject(multipartFile);
    }

    // 列出所有存储桶名称
    @PostMapping("/list")
    public List<String> list() throws Exception {
        return this.minioConfig.listBucketNames();
    }

    // 创建存储桶
    @PostMapping("/createBucket")
    public boolean createBucket(String bucketName) throws Exception {
        return this.minioConfig.makeBucket(bucketName);
    }

    // 删除存储桶
    @PostMapping("/deleteBucket")
    public boolean deleteBucket(String bucketName) throws Exception {
        return this.minioConfig.removeBucket(bucketName);
    }

    // 列出存储桶中的所有对象名称
    @PostMapping("/listObjectNames")
    public List<String> listObjectNames(String bucketName) throws Exception {
        return this.minioConfig.listObjectNames(bucketName);
    }

    // 删除一个对象
    @PostMapping("/removeObject")
    public boolean removeObject(String bucketName, String objectName) throws Exception {
        return this.minioConfig.removeObject(bucketName, objectName);
    }

    // 文件访问路径
    @PostMapping("/getObjectUrl")
    public String getObjectUrl(String bucketName, String objectName) throws Exception {
        return this.minioConfig.getObjectUrl(bucketName, objectName);
    }
}

6、测试(上传)

开发中上传接口用得较多,其他接口可自行测试。 

三、Vue+Element-ui前端交互

 

# npm下载element-ui

npm install element-ui -S

// 引入ElementUI
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
<template>
  <div id="app">
    <el-upload
        class="avatar-uploader"
        action="http://127.0.0.1:8081/test/upload"
        :show-file-list="false"
        :on-success="handleAvatarSuccess"
        :before-upload="beforeAvatarUpload">
      <img v-if="imageUrl" :src="imageUrl" class="avatar">
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageUrl: ''
    };
  },
  methods: {
    handleAvatarSuccess(res, file) {
      this.imageUrl = URL.createObjectURL(file.raw);
    },
    beforeAvatarUpload(file) {
      const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isJPG) {
        this.$message.error('上传头像图片只能是 jpg或png 格式!');
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!');
      }
      return isJPG && isLt2M;
    }
  }
}
</script>

<style lang="less">
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  left: 200px;
  top: 120px;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409EFF;
}
.avatar-uploader-icon {
  position: relative;
  top: 80px;
  font-size: 28px;
  color: #8c939d;
  width: 389px;
  height: 204px;
  line-height: 178px;
  text-align: center;
}
.avatar {
  width: 389px;
  height: 204px;
  display: block;
}
</style>

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

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

相关文章

基于OpenCV的自动报靶识别实验

基于OpenCV的自动报靶识别实验 问题方案实验结论 问题 户外胸环靶自动报靶问题&#xff0c;目前是通过声电等方式来识别&#xff0c;成本较高&#xff0c;本文尝试使用图像处理的方法来识别。 方案 前提&#xff1a;固定相机 确定靶子的四个顶点&#xff1a;目前使用人工手…

使用imp和exp命令对orcale进行导入和导出

docker 进行orcale 查看这篇文章 https://editor.csdn.net/md/?articleId131026846 1、进入orcale 1、进入orcale容器 docker exec -it oracle11g bash2、orcale连接sysdba用户 进入root su root密码&#xff1a;helowin切换到oracle用户 su oracle使用sqlplus登录test用户…

chatgpt赋能python:Python中如何删除字符串中某个字符

Python中如何删除字符串中某个字符 Python是一种功能强大的编程语言&#xff0c;许多开发人员喜欢使用它来编写应用程序。字符串是Python中的常见数据类型之一&#xff0c;可用于存储文本。有时&#xff0c;我们可能需要删除字符串中的某个字符。本文将介绍如何在Python中使用…

GDB的学习

目录&#xff1a; 什么是gdb&#xff1f;gdb的安装gdb的使用 gdb的一些骚操作watch命令的使用调试core文件 什么是gdb&#xff1f; gdb的全称是GNU debugger&#xff0c;看名字就知道 gdb 是用来对程序进行 debug 的&#xff0c;不管是学习还是工作中&#xff0c;用好gdb&…

redis五种数据类型具体时候的底层编码

redis随着值的类型不同&#xff0c;其在底层编码类型会不相同。目前现有的编码格式有 #define OBJ_ENCODING_RAW 0 /* Raw representation */ #define OBJ_ENCODING_INT 1 /* Encoded as integer */ #define OBJ_ENCODING_HT 2 /* Encoded as hash table */ #def…

RabbitMQ集群部署之普通模式

1.集群分类 在RabbitMQ的官方文档中&#xff0c;讲述了两种集群的配置方式&#xff1a; 普通模式&#xff1a;普通模式集群不进行数据同步&#xff0c;每个MQ都有自己的队列、数据信息&#xff08;其它元数据信息如交换机等会同步&#xff09;。例如我们有2个MQ&#xff1a;m…

chatgpt赋能python:Python怎么再加一个的SEO

Python怎么再加一个的SEO 作为一名有10年Python编程经验的工程师&#xff0c;我深知如何将Python项目优化为搜索引擎友好的代码。当谈到SEO时&#xff0c;构建优化的代码比任何其他技术都更加重要。在本文中&#xff0c;我将介绍一些Python中的关键SEO技巧&#xff0c;并强调如…

Spring 事务管理方案和事务管理器及事务控制的API

目录 一、事务管理方案 1. 修改业务层代码 2. 测试 二、事务管理器 1. 简介 2. 在配置文件中引入约束 3. 进行事务配置 三、事务控制的API 1. PlatformTransactionManager接口 2. TransactionDefinition接口 3. TransactionStatus接口 往期专栏&文章相关导读 …

【前端 - CSS】第 11 课 - 选择器

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、缘起 2、基础选择器 2.1、标签选择器 2.2、类选择器 2.3、id 选择器 2.4、通配符选择器 3、画盒子 4、总结 1、缘…

chatgpt赋能python:如何使用Python删除变量中的数据?

如何使用Python删除变量中的数据&#xff1f; Python是一种非常流行的编程语言&#xff0c;许多开发人员使用它来开发高效和可靠的应用程序。在处理数据时&#xff0c;Python提供了一些内置功能来执行一些基本任务。本文将探讨如何使用Python删除变量中的数据的方法。 什么是…

差动保护原理

差动保护是输入的两端CT矢量差&#xff0c;当达到设定的动作值时启动动作元件。保护范围在输入的两端CT之间的设备&#xff08;可以是线路&#xff0c;发电机&#xff0c;电动机&#xff0c;变压器等电气设备&#xff09; 什么是差动保护 电流差动保护是中的一种保护。正相序是…

UDP协议和TCP协议

目录 UDP TCP 通过序列号与确认应答提高可靠性 为什么TCP是三次握手 为什么是四次挥手 超时重传机制 流控制 利用窗口控制提高速度 窗口控制与重发控制 拥塞控制 延迟确认应答 捎带应答 UDP UDP是不具有可靠性的数据报协议。细微的处理它会交给上层的应用去完成。…

总结一下js的浅拷贝和深拷贝

js中对象的赋值是通过将一个对象的引用赋值给另一个变量&#xff0c;两个变量指向同一个内存地址。这意味着如果更改其中一个对象的值&#xff0c;另一个对象的值也会更改。 浅拷贝是将一个对象的值复制给另一个对象&#xff0c;但如果对象中包含对其他对象的引用&#xff0c;…

Linux虚拟网络设备---之Veth pair详解

本文目录 1、我们可以用以下命令来创建veth pair: veth0----veth12、创建二个命名空间namespaces后&#xff0c;可以用以下命令将二个veth设备分别移入二个命名空间ns0和ns1&#xff0c;并将它们连接起来。12、或者用以下命令在创建namespaces后&#xff0c;直接在二个namespac…

设备树的引入及简明教程

首先说明&#xff0c;设备树不可能用来写驱动。 设备树只是用来给内核里的驱动程序&#xff0c;指定硬件的信息。比如LED驱动&#xff0c;在内核的驱动程序里去操作寄存器&#xff0c;但是操作哪一个引脚&#xff1f;这由设备树指定。 需要编写设备树文件(dts: device tree s…

【协议】NVMe over RoCE |nvmeof

什么是nvme nvme ssd和普通ssd区别 ssd是固态硬盘&#xff0c;普通的ssd配的是SATA口&#xff08;AHCI协议&#xff09;&#xff0c;nvme ssd配的是PCIe口&#xff08;nvme传输协议&#xff09; 相比普通SSD的SATA口&#xff0c;nvme的PCIe口有巨大的性能优势。 更多详情见&…

HTTP超详细教程

1&#xff0c;HTTP协议 1.1&#xff0c;HTTP简述 HTTP全称为超文本传输协议&#xff0c;是一种应用比较广泛的应用层协议。 那何为超文本&#xff1f; 超文本指的是传输的内容不仅仅是文本&#xff0c;比如 html&#xff0c;css&#xff0c;javaScript 等数据&#xff0c;还…

SQL使用技巧

1、行列转换&#xff1a; decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值); select decode(sign(变量1-变量2),-1,变量1,变量2) from dual; --取较小值 sign()函数根据某个值是0、正数还是负数&#xff0c;分别返回0、1、-1 例如: 变量110&#xff0c;变量220 则s…

中间件定义

中间件(middleware)是基础软件的一大类&#xff0c;属于可复用的软件范畴。中间件在操作系统软件&#xff0c;网络和数据库之上&#xff0c;应用软件之下&#xff0c;总的作用是为处于自己上层的应用软件提供运行于开发的环境&#xff0c;帮助用户灵活、高效的开发和集成复杂的…

CTFHub | 读取源代码

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…