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

news2024/12/23 4:25:00

本文介绍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是否成功创建。
在这里插入图片描述

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

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

相关文章

安全代码审计实施标准学习笔记

声明 本文是学习GB-T 39412-2020 信息安全技术 代码安全审计规范. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 资源使用安全缺陷审计列表 资源管理 审计指标&#xff1a;应避免重复释放资源。 审计人员应检查代码是否存在重复释放资源的情况。重…

Opencv+Python笔记(九)模板匹配

模板匹配 模板匹配常用于对象检测&#xff0c;且实现简单计算效率高。但如果输入图像中存在变化因素如旋转、缩放、视角变化等&#xff0c;模板匹配很容易失效 模板匹配原理&#xff1a; 1.匹配方式为模板 (a * b) 在原图像 (m * n) 上滑动 使用参数method中指定的方法&#…

云原生(docker+k8s+阿里云)

Gitee-Kubernetes学习 kubectl备忘清单 k8s官方文档-task [云原生-kubectl命令详解] ingress详解 ingress官方文档 云原生-语雀-架构师第一课 如上图&#xff0c;服务器有公网ip和私网ip&#xff0c;公网ip是外部访问服务器用的&#xff0c;重启一次实例就变化了&#xff0c;如…

常用数据结构与颜色空间

常用数据结构与颜色空间 矩阵和图像类型 图像可能是灰度&#xff0c;彩色&#xff0c;4 通道的(RGBalpha)&#xff0c;其中每个通道可以包含任意的整数或浮点数。因此&#xff0c;该类型比常见的、易于理解的3通道 8位 RGB 图像更通用。 RBG颜色空间、 HSV/HLS颜色空间、 Lab…

Blender 3.5 面的操作(二)

目录 1. 面操作1.1 面的切割1.2 整体切分1.3 面的法向1.4 正面、背面1.5 翻转法向1.6 填充面1.7 X-Ray 透视模式 1. 面操作 1.1 面的切割 切割工具 Knife&#xff0c;快捷键 k 选中一个面 按k键&#xff0c;进入切割工具&#xff08;建议使用快捷键切割&#xff09;&#xff…

crossover可以安装什么软件?支持的软件列表

CrossOver是一款可以在Mac和Linux等操作系统上运行Windows软件&#xff0c;而无需在计算机上安装Windows操作系统。这款软件的核心技术是Wine&#xff0c;它是一种在Linux和macOS等操作系统上运行Windows应用程序的开源软件。本文将会对CrossOver进行详细介绍&#xff0c;并回答…

“SCSA-T学习导图+”系列:IPSec VPN原理与应用

本期引言&#xff1a; 本章主要讲解IPSec VPN相关理论概念&#xff0c;工作原理。从安全和加密原理入手&#xff0c;讲解了IPSec 在VPN对等体设备实现的安全特性&#xff0c;如数据的机密性、数据的完整性&#xff0c;数据验证等。重点分析IPSec封装模式&#xff0c;IPSec安全…

技术解读丨多模数据湖:助力AI技术,推动内容管理平台智能化升级

随着数字化时代的到来&#xff0c;数据已经成为企业的重要资产之一。因此&#xff0c;构建高效的内容管理平台变得至关重要。本文重点介绍SequoiaDB多模数据湖技术在内容管理平台中的应用和成效&#xff0c;以及其对企业非结构化数据管理和AI的推动作用。 随着数字化时代的到来…

Vue3技术6之toRef和toRefs、shallowReactive与shallowRef、readonly与shallowReadonly

Vue3技术6 toRef和toRefstoRefApp.vueDemo.vue toRefsApp.vueDemoTwo.vue 总结 shallowReactive与shallowRefshallowReactiveApp.vueDemo.vue shallowRefDemo.vue 总结 readonly与shallowReadonlyApp.vueDemo.vueDemoTwo.vue总结 toRef和toRefs toRef App.vue <template&…

SpringCloud入门实战(七)-Hystrix服务限流

&#x1f4dd; 学技术、更要掌握学习的方法&#xff0c;一起学习&#xff0c;让进步发生 &#x1f469;&#x1f3fb; 作者&#xff1a;一只IT攻城狮 。 &#x1f490;学习建议&#xff1a;1、养成习惯&#xff0c;学习java的任何一个技术&#xff0c;都可以先去官网先看看&…

电子行业数字工厂管理系统的生产管理模式是什么

随着电子行业的不断发展&#xff0c;数字工厂管理系统在生产管理中的应用越来越广泛。数字工厂系统是一种综合管理系统&#xff0c;它将企业的采购、生产、销售、财务、人力资源等多个方面进行整合&#xff0c;实现了企业资源的有效整合和管理效率的提升。电子行业数字工厂系统…

vue 使用 threejs 加载第三方模型

threejs 加载第三方模型 接专栏的上一篇博文&#xff0c;这是加载第三方模型相关的。这篇博文拖了很久了哈&#xff0c;简单说一下吧&#xff0c;本来不想写了的&#xff0c;觉得相对来说比较简单&#xff0c;但是还是稍微一扯。为啥要加载第三方呢&#xff0c;上一篇我们绘制的…

人工智能:技术的进步与未来展望

一、引言 1.人工智能的定义 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是指由人类创造的具有某种程度上模拟、延伸或超越人类智能的技术。AI技术使计算机能够从数据中学习、推理、适应并执行类似人类大脑所进行的任务。这些任务包括图像识别、…

【Linux命令行与Shell脚本编程】三,Linux文件系统

Linux命令行与Shell脚本编程 第三章 Linux文件系统 文章目录 Linux命令行与Shell脚本编程三.Linux文件系统3.1,查看文件3.1.1,ls 命令 选项和参数3.1.2,过滤输出列表 3.2, 处理文件3.2.1,touch 创建文件3.2.2,cp 复制文件cp -i 覆盖询问cp -R 递归cp命令中使用通配符 3.2.3,ta…

NFS网络文件共享服务

NFS网络文件共享服务 NFS&#xff08;network file system&#xff09;网络文件系统 可以把对方主机资源直接挂载到自己电脑上&#xff0c;比FTP更加方便 明文传输 没有认证机制 安全性很差 只在局域网使用 依赖RPC(远程过程调用&#xff09; 需要安装nfs-utils(提供NFS服务)…

对话西门子Mendix:低代码与亚马逊云科技Serverless的底层融合,助力企业提效降本...

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 3月30日 亚马逊云科技举办了主题为“全面拥抱Serverless时代”的创新大会&#xff0c;分享了亚马逊云科技17年引领Serverless发展的技术创新、应用场景以及全球客户的创新实践。 会上&#xff0c;亚马逊云科技大中华区产品部…

RocketMQ高级概念

一 RocketMQ核心概念 1.消息模型&#xff08;Message Model&#xff09; RocketMQ主要由 Producer、Broker、Consumer 三部分组成&#xff0c;其中Producer 负责⽣产消息&#xff0c;Consumer 负责消费消息&#xff0c;Broker 负责存储消息。Broker 在实际部署过程中对应⼀台…

[MLIR] 转换流程详解(以Toy接入为例)

参考资料&#xff1a; [MLIR] 转换流程详解(以Toy接入为例) - 知乎 (zhihu.com) 在本文中我们使用 toy 语言接入 MLIR&#xff0c;最终转化为 LLVM IR (或目标代码)为例&#xff0c;来讲解 MLIR 的转换流程。具体的流程如下&#xff1a; .toy 源文件 → AST → MLIRGen(遍历AST…

【SSM】整合开发

文章目录 1.ssm整合过程1.1步骤1.2 Spring整合SpringMVC的问题 2.准备工作2.1 添加依赖2.2 创建数据库 3.相关配置3.1 整合Spring和Mybatis3.2 引入SpringMVC3.3 spring整合入web项目 4.测试整合效果 1.ssm整合过程 1.1步骤 &#xff08;1&#xff09;Spring整合MyBatis 通过…

PHP数组的功能及实现案例

目录 前言 一、什么是数组 二、创建关联数组 1.1运行流程&#xff08;思想&#xff09; 1.2代码段 1.3运行截图 三、创建索引数组 1.1运行流程&#xff08;思想&#xff09; 1.2代码段 1.3运行截图 前言 1.若有选择&#xff0c;可实现在目录里进行快速查找&#xff…