SpringBoot整合Minio,一篇带你入门使用Minio

本文介绍SpringBoot如何整合Minio,解决文件存储问题

文章目录

  • 前言
  • 环境搭建
    • 项目环境搭建
      • 添加依赖库
      • yml配置
    • Docker安装minio
  • 代码实现
    • MiniConfig
    • service
    • controller
  • 测试

前言

参考链接:

  • 官网

环境搭建

项目环境搭建

将minio单独封装成一个module,上层导入依赖,比如api module
在这里插入图片描述
在api 模块,测试接口
在这里插入图片描述

添加依赖库

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-learn</artifactId>
        <groupId>org.ym</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>learn-common-minio</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.4.5</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
    </dependencies>

</project>

yml配置

application.yml配置,配置minio基本信息

server:
  port: 9203

minio:
  endpoint: http://127.0.0.1:9000
  bucketName: learn-minio
  accessKey: minioadmin
  secretKey: minioadmin

spring:
  application:
    name: learn-api
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

Docker安装minio

首先要创建本机data目录/Users/yangmiao/config/docker/data/minio,至于Docker常见命令的使用,参考我的另一篇文章Docker常见命令使用

sudo docker run -p 9000:9000 -p 9090:9090 \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=minioadmin" \
-e "MINIO_SECRET_KEY=minioadmin" \
-v /Users/yangmiao/config/docker/data/minio:/data \
minio/minio server \
/data --console-address ":9090" -address ":9000"

镜像启动成功后,浏览器访问:http://localhost:9090/,输入用户名和密码minioadmin。
在这里插入图片描述

代码实现

MiniConfig

package com.ym.learn.minio.config;

import com.ym.learn.minio.service.MinioService;
import com.ym.learn.minio.service.impl.MinioServiceImpl;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 23:04
 * @Desc: minio基础配置
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
    /**
     * 服务地址
     */
    private String endpoint;
    /**
     * 访问key
     */
    private String accessKey;
    /**
     * 密钥
     */
    private String secretKey;
    /**
     * 桶名称
     */
    private String bucketName;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }

    @Bean
    public MinioService minioService(){
        return new MinioServiceImpl();
    }
}

在这里插入图片描述

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.ym.learn.minio.config.MinioConfig

service

package com.ym.learn.minio.service;

import com.ym.learn.minio.config.MinioConfig;
import io.minio.MinioClient;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 23:09
 * @Desc: minio服务
 */
public interface MinioService {
    /**
     * 判断bucket是否存在
     * @param bucketName
     * @return
     */
    boolean bucketExists(String bucketName);

    /**
     * 创建bucket
     * @param bucketName
     * @return
     */
    boolean createBucket(String bucketName);

    /**
     * 删除bucket
     * @param bucketName
     * @return
     */
    boolean removeBucket(String bucketName);

    /**
     * 获取所有的bucket
     * @return
     */
    List<Bucket> getAllBuckets();

    /**
     * 上传文件
     * @param multipartFile
     * @return
     */
    String upload(MultipartFile multipartFile);

    /**
     * 下载文件
     * @param fileName
     * @param res
     */
    void download(String fileName, HttpServletResponse res);

    /**
     * 删除文件
     * @param fileName
     * @return
     */
    boolean remove(String fileName);

    /**
     * 预览文件
     * @param fileName
     * @return
     */
    String preview(String fileName);

    /**
     * 查看所有的文件对象
     * @return
     */
    List<Item> getAllFiles();

}

package com.ym.learn.minio.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.ym.learn.minio.config.MinioConfig;
import com.ym.learn.minio.service.MinioService;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 23:12
 * @Desc:
 */
@Service
@Slf4j
public class MinioServiceImpl implements MinioService {
    @Autowired
    private MinioConfig minioConfig;
    @Autowired
    private MinioClient minioClient;

    @Override
    public boolean bucketExists(String bucketName) {
        if (StrUtil.isEmpty(bucketName)){
            return false;
        }
        boolean res = false;
        try {
            res = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            log.error("bucketExists error: {}",e.getMessage());
            e.printStackTrace();
            return false;
        }
        return res;
    }

    @Override
    public boolean createBucket(String bucketName) {
        if (StrUtil.isEmpty(bucketName)){
            return false;
        }
        try {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }catch (Exception e){
            log.error("createBucket error: {}",e.getMessage());
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public boolean removeBucket(String bucketName) {
        if (StrUtil.isEmpty(bucketName)){
            return false;
        }
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
        }catch (Exception e){
            log.error("removeBucket error: {}",e.getMessage());
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public List<Bucket> getAllBuckets() {
        try {
            return minioClient.listBuckets();
        }catch (Exception e){
            log.error("getAllBuckets error: {}",e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String upload(MultipartFile multipartFile) {
        if (multipartFile == null){
            return null;
        }
        String fileName = multipartFile.getOriginalFilename();
        if (StrUtil.isBlank(fileName)){
            throw new RuntimeException("upload fail!");
        }
        fileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))+"_"+UUID.randomUUID().toString().replaceAll("-","")+
                fileName.substring(fileName.lastIndexOf("."));
        log.debug("upload: fileName {}",fileName);
        try {
            minioClient.putObject(PutObjectArgs.builder()
                            .bucket(minioConfig.getBucketName())
                            .object(fileName)
                            .stream(multipartFile.getInputStream(), multipartFile.getSize(), -1)
                            .contentType(multipartFile.getContentType())
                            .build());
        } catch (Exception e) {
            log.error("upload error: {}",e.getMessage());
            e.printStackTrace();
            return null;
        }
        String url = minioConfig.getEndpoint()+"/"+minioConfig.getBucketName()+"/"+fileName;
        return url;
    }

    @Override
    public void download(String fileName, HttpServletResponse res) {
        if (StrUtil.isEmpty(fileName)){
            return;
        }
        ByteArrayOutputStream out = null;
        try {
            GetObjectResponse objectResponse = minioClient.getObject(GetObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(fileName)
                    .build());

            out = new ByteArrayOutputStream();
            IoUtil.copy(objectResponse,out);
            res.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            res.setContentLength(out.toByteArray().length);
            res.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            try(ServletOutputStream stream = res.getOutputStream()){
                stream.write(out.toByteArray());
                stream.flush();
            }
        }catch (Exception e){
            log.error("download error: {}",e.getMessage());
            e.printStackTrace();
        }finally {
            if (out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public boolean remove(String fileName) {
        if (StrUtil.isEmpty(fileName)){
            return false;
        }
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).build());
        }catch (Exception e){
            log.error("remove error: {}",e.getMessage());
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public String preview(String fileName) {
        if (StrUtil.isEmpty(fileName)){
            return null;
        }
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(fileName)
                    .method(Method.GET)
                    .build());
        }catch (Exception e){
            log.error("preview error: {}",e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public List<Item> getAllFiles() {
        List<Item> itemList = new ArrayList<>();
        try {
            Iterable<Result<Item>> listObjects = minioClient.listObjects(
                    ListObjectsArgs.builder()
                            .bucket(minioConfig.getBucketName())
                            .build());
            try {
                for (Result<Item> item:listObjects){
                    itemList.add(item.get());
                }
            }catch (Exception e){
                log.error("getAllFiles error, get item fail! {}",e.getMessage());
                e.printStackTrace();
                return null;
            }
        }catch (Exception e){
            log.error("getAllFiles error {}",e.getMessage());
            e.printStackTrace();
            return null;
        }
        return itemList;
    }
}

controller

package com.ym.learn.api.controller;

import com.ym.learn.core.api.R;
import com.ym.learn.minio.config.MinioConfig;
import com.ym.learn.minio.service.MinioService;
import io.minio.messages.Bucket;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/22 23:00
 * @Desc:
 */
@Api(tags = "minio接口")
@RestController
@RequestMapping("/file")
@Slf4j
public class MinioController {
    @Autowired
    private MinioService minioService;
    @Autowired
    private MinioConfig minioConfig;

    @ApiOperation(value = "判断bucket是否存在")
    @GetMapping("/bucketExist")
    public R bucketExist(@RequestParam("bucketName")String bucketName){
        boolean exists = minioService.bucketExists(bucketName);
        return R.ok(exists);
    }

    @ApiOperation(value = "创建bucket")
    @GetMapping("/createBucket")
    public R createBucket(String bucketName){
        boolean ret = minioService.createBucket(bucketName);
        return R.ok(ret);
    }

    @ApiOperation(value = "删除bucket")
    @GetMapping("/removeBucket")
    public R removeBucket(String bucketName){
        boolean removeBucket = minioService.removeBucket(bucketName);
        return R.ok(removeBucket);
    }

    @ApiOperation(value = "获取所有的bucket")
    @GetMapping("/getAllBucket")
    public R getAllBucket(){
        List<Bucket> allBuckets = minioService.getAllBuckets();
        return R.ok(allBuckets);
    }

    @ApiOperation(value = "上传文件")
    @PostMapping("/uploadFile")
    public R uploadFile(@RequestParam("file") MultipartFile file){
        String upload = minioService.upload(file);
        return R.ok(upload);
    }

    @ApiOperation(value = "查看Image")
    @GetMapping("/preview")
    public R preview(String fileName){
        String preview = minioService.preview(fileName);
        return R.ok(preview);
    }

    @ApiOperation(value = "下载文件")
    @GetMapping("/downloadFile")
    public R downloadFile(String fileName, HttpServletResponse response){
        minioService.download(fileName,response);
        return R.ok();
    }

    @ApiOperation(value = "删除文件")
    @PostMapping("/removeFile")
    public R removeFile(String url){
        String objName = url.substring(url.lastIndexOf(minioConfig.getBucketName()+"/") + minioConfig.getBucketName().length()+1);
        boolean remove = minioService.remove(objName);
        return R.ok(remove);
    }![在这里插入图片描述](https://img-blog.csdnimg.cn/f9965e88a5b84d62ba029ffc86e065f3.jpeg#pic_center)


}

测试

由于项目已引入了Knife4j,本文采用了Knife4j和ApiPost测试
在这里插入图片描述
在这里插入图片描述
查看minio是否上传成功图片,以及bucket是否成功创建。
在这里插入图片描述

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

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

相关文章

LeetCode单链表OJ题目做题思路分享

目录 移除链表元素链表的中间节点链表中倒数第K个节点合并两个有序链表 移除链表元素 链接: link 题目描述&#xff1a; 思路分享&#xff1a; 我们上个博客分享了第一种方法&#xff0c;下面我们分析第二种方法&#xff1a;思路就是将每一个不等于我们要删除的值的节点依次尾…

如何快速获取已发表学术论文的期刊封面及目录(caj格式下载和caj转pdf)

目录 1 下载caj格式的封面和目录 2 CAJ格式的封面和目录转PDF格式 在进行职称评审或成果申报时&#xff0c;一般要求提交你发表的成果所在的期刊的当期封面和目录。本文就手把手带带你制作一个期刊目录。 重要提示&#xff1a;下载期刊封面和目录需要你有知网账号&#xff0…

Java读取Properties配置文件的6种方式

Java读取Properties的方式 项目结构&#xff1a;经典的maven项目结构 配置文件1和2内容一致&#xff1a; jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urlmysql://localhost:3306/database?useUnicodetrue&characterEncodingutf-8&serverTimezoneAsia/Shanghai jdbc.…

【深度学习】计算机视觉(13)——模型评价及结果记录

1 Tensorboard怎么解读&#xff1f; 因为意识到tensorboard的使用远不止画个图放个图片那么简单&#xff0c;所以这里总结一些关键知识的笔记。由于时间问题&#xff0c;我先学习目前使用最多的功能&#xff0c;大部分源码都包含summary的具体使用&#xff0c;基本不需要自己修…

找高清无水印视频素材,就上这9个网站。

推荐几个我的视频素材库&#xff0c;有免费、收费、商用&#xff0c;希望对大家有帮助&#xff01; 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 菜鸟图库可以找到设计、办公、图片、视频、音频等各种素材。视频素材就有上千个&#xff0c;全部都很高清&…

unityt光线透射目标

介绍 在Unity中&#xff0c;光线透射目标通常指的是在场景中放置的一些物体&#xff0c;用于模拟光线从一个物体透过到另一个物体的效果。canvas子物体组件中&#xff0c;勾不勾选“光线透射目标”有什么区别&#xff1f; 方法 在Canvas子物体组件中勾选“光线透射目标”时&…

Python基础合集 练习17(类与对象)

class Dog: pass papiDog() print(papi) print(type(papi)) 构建方法 创建类过后可以定义一个特殊的方法。在python中构建方法是__init__(),init()必须包含一个self参数 class pig(): #def__init__(self) -> None&#xff1a; print(‘你好’) pipgpig() 属性和方法 cl…

C++好难(2):类和对象(上篇)

okay&#xff0c;从这里开始&#xff0c;就进入c比较难的部分了~啊啊啊&#xff01;&#xff01;&#xff01; (﹃ԅ) 坚持坚持啦 ~ ᵎ(•̀㉨•́)و ̑̑ 【本章目标】 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 5.类的作用域 6.类的实…

(1)QT基础铺垫

目录 1.Qt特性 2. 新建项目 3. 工作目录与构建目录 4. 工作目录 4.1 .pro 项目配置文件 4.2 dialog.h 4.3 dialog.cpp 4.4 main.cpp 5. 帮助文档 6. 调试信息 1.Qt特性 Qt经常被当作是一个基于c语言的gui开发框架&#xff0c;但是这并不是qt的全部&#xff0c;除了开…

JavaWeb( 二 ) URL

1.4.URL统一资源定位符 URL代表Uniform Resource Locator 统一资源定位符&#xff0c;也叫 URL地址 。是用于标识和定位Web上资源的地址&#xff0c;通常用于在Web浏览器中访问网站和文件。 URL由若干部分组成&#xff0c;scheme:// host : port / path 例如&#xff1a; htt…

WxGL应用实例:绘制点云

WxGL附带了几个工具函数&#xff0c;其中read_pcfile用来解析.ply和.pcd格式的点云文件&#xff0c;该函数返回一个PointCloudData类实例&#xff0c;包含以下属性&#xff1a; PointCloudData.ok - 数据是否可用&#xff0c;布尔型PointCloudData.info - 数据可用性说明&…

《通过十几轮数据进行模型训练,实现精确的无创血糖测量的演绎学习》阅读笔记

目录 0 演绎学习 1 论文摘要 2 论文十问 3 论文亮点与不足之处 4 与其他研究的比较 5 实际应用与影响 6 个人思考与启示 参考文献 0 演绎学习 在本文中&#xff0c;DL指的是Deduction Learning&#xff0c;即演绎学习方法。该方法是一种机器学习方法&#xff0c;通过使…

简单毛概刷题网页制作 3.0(拖欠近一年版)

原因是大概一年之前学校的毛概期末刷题网站突然崩了&#xff0c;但是一直没有修复。当时眼看着复习时间逐渐被压缩&#xff0c;自己啥也做不了&#xff0c;遂自学前端完成毛概刷题网页一枚。 最早的毛概刷题网站仅仅是 1.0 版本&#xff08;传送门&#xff09;&#xff0c;功能…

STM32F4_USMART调试组件

目录 1. USMART是什么&#xff1f; 2. USMART的特点 3. USMART实现流程 4. USMART组件 5. 在usmart_config.c中添加想要被USMART调用的函数 6. 实验程序 6.1 main.c 6.2 usmart.c 6.3 usmart.h 7. USMART调试的优越性说明 1. USMART是什么&#xff1f; USMART 是 AL…

org.apache.poi 设置 Excel 单元格颜色 RGB

一、背景说明 在使用 org.apache.poi 导出 Excel 时&#xff0c;需要设置部分单元格的颜色。 可以使用方法&#xff1a;org.apache.poi.ss.usermodel.CellStyle.setFillForegroundColor() 和 org.apache.poi.ss.usermodel.CellStyle.setFillPattern() 来设置单元格的颜色和填…

低频量化之 可转债 配债数据及策略 - 全网独家

目录 历史文章可转债配债数据 待发转债&#xff08;进展统计&#xff09;待发转债&#xff08;行业统计&#xff09;待发转债&#xff08;5证监会通过&#xff0c;PE排序&#xff09;待发转债&#xff08;5证监会通过&#xff0c;安全垫排序&#xff09;待发转债&#xff08;5证…

【算法】一文彻底搞懂ZAB算法

文章目录 什么是ZAB 算法&#xff1f;深入ZAB算法1. 消息广播两阶段提交ZAB消息广播过程 2. 崩溃恢复选举参数选举流程 ZAB算法需要解决的两大问题1. 已经被处理的消息不能丢2. 被丢弃的消息不能再次出现 最近需要设计一个分布式系统&#xff0c;需要一个中间件来存储共享的信息…

Java 怎样实现代理模式,有什么优缺点

一、介绍 代理模式是一种常见的设计模式&#xff0c;它可以为其他对象提供一种代理以控制对这个对象的访问。代理对象具有与被代理对象相同的接口&#xff0c;客户端无需知道代理对象和被代理对象的区别。代理模式可以应用于各种不同的场景&#xff0c;例如远程代理、虚拟代理…

SpringBoot整合Mybatis-plus实现多级评论

在本文中&#xff0c;我们将介绍如何使用SpringBoot整合Mybatis-plus实现多级评论功能。同时&#xff0c;本文还将提供数据库的设计和详细的后端代码&#xff0c;前端界面使用Vue2。 数据库设计 本文的多级评论功能将采用MySQL数据库实现&#xff0c;下面是数据库的设计&…

vcruntime140.dll无法继续执行代码?vcruntime140.dll如何修复?只需要3步即可

vcruntime140.dll是用于Microsoft Visual C Redistributable&#xff08;可再发行组件&#xff09;的一部分&#xff0c;它是一个动态链接库文件&#xff0c;包含了该软件包提供的运行库。在许多应用程序和游戏中&#xff0c;vcruntime140.dll文件经常被使用。如果该文件缺失或…