当前位置: 首页 > news >正文

Spring Boot集成Minio插件快速入门

1 Minio介绍

MinIO 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几 kb 到最大 5T 不等。以下是 MinIO 的一些主要特点和优势:

  1. 兼容性: MinIO 使用标准的 Amazon S3 API,这意味着它与现有的 S3 应用程序和工具兼容,可以无缝替换 Amazon S3。

  2. 高性能: MinIO 借助于其分布式架构和优化的存储引擎,在处理大规模数据时表现出色。它可以水平扩展以满足各种工作负载需求。

  3. 轻量级: MinIO 的设计注重简单性和效率,因此它是一个轻量级的服务。这使得它易于部署、管理和维护。

  4. 高可用性: MinIO 支持数据的多副本复制和故障转移,确保数据的可靠性和高可用性。它可以在节点故障时自动进行数据修复和重平衡。

  5. 安全性: MinIO 提供多种安全功能,包括加密传输、访问控制列表 (ACLs)、策略管理和身份验证机制,以确保数据的保密性和完整性。

  6. 灵活性: MinIO 可以在各种环境中部署,包括本地数据中心、云环境和容器化环境。它支持多种存储后端,包括本地磁盘、分布式文件系统和对象存储。

2 Minio环境搭建

2.1 docker环境下

采用docker-compose搭建:

# 可参考 https://docs.min.io/docs/minio-docker-quickstart-guide.html
version: '3'
services:minio:image: minio/minio:latest                                    # 原镜像`minio/minio:latest`container_name: minio                                        # 容器名为'minio'restart: unless-stopped                                              # 指定容器退出后的重启策略为始终重启,但是不考虑在Docker守护进程启动时就已经停止了的容器volumes:                                                     # 数据卷挂载路径设置,将本机目录映射到容器目录- "./minio/data:/data"- "./minio/minio:/minio"- "./minio/config:/root/.minio"environment:                                      # 设置环境变量,相当于docker run命令中的-eTZ: Asia/ShanghaiLANG: en_US.UTF-8MINIO_PROMETHEUS_AUTH_TYPE: "public"MINIO_ACCESS_KEY: "root"                        # 登录账号MINIO_SECRET_KEY: "password"                    # 登录密码command: server /data  --console-address ":9001"logging:driver: "json-file"options:max-size: "100m"ports:                              # 映射端口- "9000:9000" # 文件上传&预览端口- "9001:9001" # 控制台访问端口

启动服务:

docker-compose -f docker-compose-minio.yml -p minio up -d

启动后:

访问地址:ip地址:9001/minio 登录账号密码:root/password

2.2 Linux环境下(非docker容器下)

下载并授权限:

wget https://dl.min.io/sever/minio/release/linux-amd64/minio
chmod +x minio    //添加执行权限

启动minio服务:

MINIO_ROOT_USER=root MINIO_ROOT_PASSWORD=password ./minio server /data/minio/data --console-address ":9001"
  • 用户名为“root”
  • 密码为“password”
  • 数据存储路径为"/data/minio/data"
  • 控制台页面的访问端口为"9091"

2.3 Windows环境下

下载资源:

MinIO | S3 & Kubernetes Native Object Storage for AI

创建文件夹:

下载完成之后再合适的目录下创建三个必要的文件夹 ,分别是bin,data,logs文件夹

安装位置根据自身需求选择就好,我选在D盘的minio文件下

在这里插入图片描述
将minio.exe放入到bin中

然后执行命令(账号密码可通过命令行自行配置):

D:\minio\bin\minio.exe server D:\minio\data --console-address ":9001" --address ":9000"

2.4 运行成功后访问

在这里插入图片描述

3 springboot整合代码实现

3.1 写代码前的准备

创建桶:

在这里插入图片描述
获取accessKey和secretKey:

在这里插入图片描述

3.2 编写代码

application.yaml:

server:port: 8088minio:endpoint: http://127.0.0.1:9000 #Minio服务所在地址bucketName: miniotest #存储桶名称accessKey: JW38e2AR9G5DgvmUCa51 #访问的keysecretKey: rK5zgSxAyUwqgIfSWmec9osxDPvyN2qoEqX3MxZa #访问的秘钥

pom.xml:

<?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>springboot-demo</artifactId><groupId>com.wkf</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>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.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.20</version></dependency><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.2</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.11</version></dependency></dependencies>
</project>

MinioConfig.java:

package com.wkf.minio.config;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;@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {private String endpoint;private String accessKey;private String secretKey;private String bucketName;@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();}
}

OSSController.java:

package com.wkf.minio.controller;import com.wkf.minio.config.MinioConfig;
import com.wkf.minio.util.MinioUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
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.io.InputStream;@Slf4j
@RestController
@RequestMapping("/oss")
public class OSSController {@Autowiredprivate MinioUtils minioUtils;@Autowiredprivate MinioConfig minioConfig;/*** file upload** @param file*/@PostMapping("/upload")public String upload(@RequestParam("file") MultipartFile file) {try {//file nameString fileName = file.getOriginalFilename();String newFileName = System.currentTimeMillis() + "." + StringUtils.substringAfterLast(fileName, ".");//typeString contentType = file.getContentType();minioUtils.uploadFile(minioConfig.getBucketName(), file, newFileName, contentType);return "upload success";} catch (Exception e) {e.printStackTrace();log.error("upload fail");return "upload fail";}}/*** delete** @param fileName*/@DeleteMapping("/")public void delete(@RequestParam("fileName") String fileName) {minioUtils.removeFile(minioConfig.getBucketName(), fileName);}/*** get file info** @param fileName* @return*/@GetMapping("/info")public String getFileStatusInfo(@RequestParam("fileName") String fileName) {return minioUtils.getFileStatusInfo(minioConfig.getBucketName(), fileName);}/*** get file url** @param fileName* @return*/@GetMapping("/url")public String getPresignedObjectUrl(@RequestParam("fileName") String fileName) {return minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), fileName);}/*** file download** @param fileName* @param response*/@GetMapping("/download")public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {try {InputStream fileInputStream = minioUtils.getObject(minioConfig.getBucketName(), fileName);response.setHeader("Content-Disposition", "attachment;filename=" + fileName);response.setContentType("application/force-download");response.setCharacterEncoding("UTF-8");IOUtils.copy(fileInputStream, response.getOutputStream());} catch (Exception e) {log.error("download fail");}}}

MinioUtil.java:

package com.wkf.minio.util;import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;/*** MinIO Utils**/
@Slf4j
@Component
@RequiredArgsConstructor
public class MinioUtils {private final MinioClient minioClient;/******************************  Operate Bucket Start  ******************************//***  init Bucket  when start SpringBoot container* create bucket if the bucket is not exists** @param bucketName*/@SneakyThrows(Exception.class)private void createBucket(String bucketName) {if (!bucketExists(bucketName)) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}}/*** verify Bucket is exist?,true:false** @param bucketName* @return*/@SneakyThrows(Exception.class)public boolean bucketExists(String bucketName) {return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}/*** get Bucket strategy** @param bucketName* @return*/@SneakyThrows(Exception.class)public String getBucketPolicy(String bucketName) {return minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());}/*** get all Bucket list** @return*/@SneakyThrows(Exception.class)public List<Bucket> getAllBuckets() {return minioClient.listBuckets();}/*** Get related information based on bucketName** @param bucketName* @return*/@SneakyThrows(Exception.class)public Optional<Bucket> getBucket(String bucketName) {return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();}/*** Delete Bucket based on bucketName, true: deletion successful; false: deletion failed, file may no longer exist** @param bucketName* @throws Exception*/@SneakyThrows(Exception.class)public void removeBucket(String bucketName) {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}/******************************  Operate Bucket End  ******************************//******************************  Operate Files Start  ******************************//*** check file is exist** @param bucketName* @param objectName* @return*/public boolean isObjectExist(String bucketName, String objectName) {boolean exist = true;try {minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());} catch (Exception e) {log.error("[MinioUtils]>>>>check file exist, Exception:", e);exist = false;}return exist;}/*** check directory exist?** @param bucketName* @param objectName* @return*/public boolean isFolderExist(String bucketName, String objectName) {boolean exist = false;try {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());for (Result<Item> result : results) {Item item = result.get();if (item.isDir() && objectName.equals(item.objectName())) {exist = true;}}} catch (Exception e) {log.error("[MinioUtils]>>>>check file exist, Exception:", e);exist = false;}return exist;}/*** Query files based on file prefix** @param bucketName* @param prefix* @param recursive* @return MinioItem*/@SneakyThrows(Exception.class)public List<Item> getAllObjectsByPrefix(String bucketName,String prefix,boolean recursive) {List<Item> list = new ArrayList<>();Iterable<Result<Item>> objectsIterator = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());if (objectsIterator != null) {for (Result<Item> o : objectsIterator) {Item item = o.get();list.add(item);}}return list;}/*** get file InputStream** @param bucketName* @param objectName* @return*/@SneakyThrows(Exception.class)public InputStream getObject(String bucketName, String objectName) {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** Breakpoint download** @param bucketName* @param objectName* @param offset* @param length* @return*/@SneakyThrows(Exception.class)public InputStream getObject(String bucketName, String objectName, long offset, long length) {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).offset(offset).length(length).build());}/*** Get the list of files under the path** @param bucketName* @param prefix* @param recursive* @return*/public Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());}/*** use MultipartFile to upload files** @param bucketName* @param file* @param objectName* @param contentType* @return*/@SneakyThrows(Exception.class)public ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, String objectName, String contentType) {InputStream inputStream = file.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType).stream(inputStream, inputStream.available(), -1).build());}/*** picture upload* @param bucketName* @param imageBase64* @param imageName* @return*/public ObjectWriteResponse uploadImage(String bucketName, String imageBase64, String imageName) {if (!StringUtils.isEmpty(imageBase64)) {InputStream in = base64ToInputStream(imageBase64);String newName = System.currentTimeMillis() + "_" + imageName + ".jpg";String year = String.valueOf(new Date().getYear());String month = String.valueOf(new Date().getMonth());return uploadFile(bucketName, year + "/" + month + "/" + newName, in);}return null;}public static InputStream base64ToInputStream(String base64) {ByteArrayInputStream stream = null;try {byte[] bytes = new BASE64Decoder().decodeBuffer(base64.trim());stream = new ByteArrayInputStream(bytes);} catch (Exception e) {e.printStackTrace();}return stream;}/*** upload local files** @param bucketName* @param objectName* @param fileName* @return*/@SneakyThrows(Exception.class)public ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) {return minioClient.uploadObject(UploadObjectArgs.builder().bucket(bucketName).object(objectName).filename(fileName).build());}/*** upload files based on stream** @param bucketName* @param objectName* @param inputStream* @return*/@SneakyThrows(Exception.class)public ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());}/*** create file or direatory** @param bucketName* @param objectName* @return*/@SneakyThrows(Exception.class)public ObjectWriteResponse createDir(String bucketName, String objectName) {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(new ByteArrayInputStream(new byte[]{}), 0, -1).build());}/*** get file info** @param bucketName* @param objectName* @return*/@SneakyThrows(Exception.class)public String getFileStatusInfo(String bucketName, String objectName) {return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()).toString();}/*** copy file** @param bucketName* @param objectName* @param srcBucketName* @param srcObjectName*/@SneakyThrows(Exception.class)public ObjectWriteResponse copyFile(String bucketName, String objectName, String srcBucketName, String srcObjectName) {return minioClient.copyObject(CopyObjectArgs.builder().source(CopySource.builder().bucket(bucketName).object(objectName).build()).bucket(srcBucketName).object(srcObjectName).build());}/*** delete file** @param bucketName* @param objectName*/@SneakyThrows(Exception.class)public void removeFile(String bucketName, String objectName) {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** batch delete file** @param bucketName* @param keys* @return*/public void removeFiles(String bucketName, List<String> keys) {List<DeleteObject> objects = new LinkedList<>();keys.forEach(s -> {objects.add(new DeleteObject(s));try {removeFile(bucketName, s);} catch (Exception e) {log.error("[MinioUtil]>>>>batch delete file,Exception:", e);}});}/*** get file url** @param bucketName* @param objectName* @param expires* @return url*/@SneakyThrows(Exception.class)public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) {GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();return minioClient.getPresignedObjectUrl(args);}/*** get file url** @param bucketName* @param objectName* @return url*/@SneakyThrows(Exception.class)public String getPresignedObjectUrl(String bucketName, String objectName) {GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).method(Method.GET).build();return minioClient.getPresignedObjectUrl(args);}/*** change URLDecoder to UTF8** @param str* @return* @throws UnsupportedEncodingException*/public String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");return URLDecoder.decode(url, "UTF-8");}
}

4 测试

在这里插入图片描述
在这里插入图片描述

5 代码仓库

https://github.com/363153421/springboot-demo/tree/master/minio

相关文章:

  • 「五度易链」企业大数据API接口开放平台上线啦!
  • EE trade:炒伦敦金的注意事项及交易指南
  • 1962springboot VUE社区服务平台系统开发mysql数据库web结构java编程计算机网页源码maven项目
  • VScode创建ROS项目 ROS集成开发环境
  • 【数学】Leetcode 69. x 的平方根【简单】
  • Linux源码阅读笔记04-实时调度类及SMP和NUMA
  • 跟《经济学人》学英文:2024年6月15日这期 The war for AI talent is heating up
  • AI与音乐:创新之光还是毁灭之剑?
  • 微型操作系统内核源码详解系列五(四):cm3下svc启动任务
  • 天马学航——智慧教务系统(移动端)开发日志三
  • 用友U9-UBF自定义报表-打印模板开发学习笔记
  • SpringBoot测试实践
  • Spark SQL 血缘解析方案
  • 【Apache Doris】周FAQ集锦:第 7 期
  • python,ipython 和 jupyter notebook 之间的关系
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • ES2017异步函数现已正式可用
  • Redash本地开发环境搭建
  • Spring Boot MyBatis配置多种数据库
  • 从setTimeout-setInterval看JS线程
  • 深度学习中的信息论知识详解
  • 使用common-codec进行md5加密
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 项目管理碎碎念系列之一:干系人管理
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • 翻译 | The Principles of OOD 面向对象设计原则
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​决定德拉瓦州地区版图的关键历史事件
  • # Apache SeaTunnel 究竟是什么?
  • ###STL(标准模板库)
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (windows2012共享文件夹和防火墙设置
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (一)、python程序--模拟电脑鼠走迷宫
  • (一)RocketMQ初步认识
  • (转)http协议
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .Net CF下精确的计时器
  • .NET NPOI导出Excel详解
  • .Net Web项目创建比较不错的参考文章
  • .net开发日常笔记(持续更新)
  • .NET框架
  • /var/spool/postfix/maildrop 下有大量文件
  • [ABC275A] Find Takahashi 题解
  • [BFS广搜]迷阵
  • [C#] 基于 Token 的鉴权与签名机制详解 接口对接鉴权 token、sign(a=1b=2c=3d=4)、Base64、参数加密、MD5
  • [CDOJ 838]母仪天下 【线段树手速练习 15分钟内敲完算合格】
  • [C和指针].(美)Kenneth.A.Reek(ED2000.COM)pdf
  • [C语言]-基础知识点梳理-文件管理
  • [E单调栈] lc2487. 从链表中移除节点(单调栈+递归+反转链表+多思路)
  • [HDU]2161Primes