【微服务】springboot整合minio详解

目录

一、前言

二、Minio 概述

2.1 Minio简介

2.1 Minio特点

三、Minio 环境搭建

3.1 部署过程

3.1.1 拉取镜像

3.1.2 启动容器

3.1.3 访问web页面

四、Minio基本使用

4.1 基本概念

4.2 上传文件演示

4.3 用户管理

4.4 Java操作Minio

4.4.1 导入依赖

4.4.2 上传文件到minio

五、springboot整合Minio

5.1 前置准备

5.1.1 引入依赖

5.1.2 核心配置文件

5.2 编码过程

5.2.1 创建一个参数配置类

5.2.2 创建minio配置类

5.2.3 创建minio文件服务类或工具类

5.2.4 编写测试接口

5.2.5 接口测试

六、写在文末


一、前言

在很多互联网产品应用中,都涉及到各种与文件存储相关的业务,随着技术的发展,关于如何解决分布式文件存储也有了比较成熟的方案,比如私有云部署下可以考虑fastdfs,阿里云对象存储oss,七牛云等,本篇将为你介绍另一种文件存储方式,即MinIO 。

二、Minio 概述

2.1 Minio简介

MinIO基于Apache License v2.0开源协议的对象存储服务,可以做为云存储的解决方案用来保存海量的图片,视频,文档,是一款高性能、分布式的对象存储系统, 可以100%的运行在标准硬件,即X86等低成本机器也能够很好的运行MinIO。

传统的存储和其他的对象存储不同的是:

它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。

2.1 Minio特点

Minio具有如下特点

  • 性能高,准硬件条件下它能达到55GB/s的读、35GB/s的写速率;
  • 部署自带管理界面;
  • MinIO.Inc运营的开源项目,社区活跃度高;
  • 提供了所有主流开发语言的SDK;
  • 基于Golang语言实现,配置简单,单行命令可以运行起来;
  • 兼容亚马逊S3云存储服务接口,适合于存储大容量非结构化的数据,一个对象文件可以是任意大小,从几kb到最大5T不等;

三、Minio 环境搭建

本文采用docker的方式快速搭建起Minio的环境,也可以通过官网下载安装包部署,官网安装包下载地址

3.1 部署过程

3.1.1 拉取镜像

docker pull minio/minio

3.1.2 启动容器

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

3.1.3 访问web页面

容器启动成功后,注意开发相关的防火墙端口即可,然后访问地址:IP:9000,即可访问Minio的web界面

输入账户和密码,登录进去之后,看到下面的效果说明Minio环境搭建完成

四、Minio基本使用

4.1 基本概念

在正式开始使用Minio之前,有必要先了解下几个相关的概念

  • bucket ,类比于文件系统的目录;
  • Object ,类比文件系统的文件;
  • Keys ,类比文件名;

4.2 上传文件演示

如下,点击创建一个新的bucket,创建完成后就可以在列表上看到这个bucket;

给当前这个bucket上传一个文件

点击文件夹图标

上传一张本地文件,上传完成后就可以看到这个文件了,也可以浏览上传的文件

4.3 用户管理

针对客户端的操作,经常需要维护相关的账号来管理,比如账户的操作权限,访问控制等;

点击,创建用户

填写用户信息,勾选权限保存即可

然后在用户列表就可以看到这个用户了

4.4 Java操作Minio

通过上面的环境搭建和操作,演示并了解了如何快速使用Minio,更多的功能可以参阅相关资料进一步学习了解,下面我们编写java代码完成文件的上传。

4.4.1 导入依赖

在当前的maven工程中导入minio的依赖,客户端具体版本可以根据你的实际需要选择

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

4.4.2 上传文件到minio

通过下面这段代码将本地的一张图片文件上传到minio的test这个bucket目录下

public static void main(String[] args) {FileInputStream inputStream = null;try {inputStream = new FileInputStream("F:\\网盘\\Title-logo.png");MinioClient client = MinioClient.builder().credentials("minio", "minio").endpoint("http://IP:9000").build();PutObjectArgs putObjectArgs = PutObjectArgs.builder().object("logo.png").contentType("image/png").bucket("test").stream(inputStream, inputStream.available(), -1).build();client.putObject(putObjectArgs);System.out.println("上传成功");} catch (Exception e) {e.printStackTrace();} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}

运行这段代码,上传成功后,去到test的目录下刷新之后可以看到文件已经上传

五、springboot整合Minio

接下来让我们看看如何在springboot中集成Minio,参考下面的操作步骤

5.1 前置准备

5.1.1 引入依赖

创建一个maven工程,引入如下相关的依赖

    <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>7.1.0</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies>

5.1.2 核心配置文件

在配置文件中添加如下内容

server:port: 8087logging:level:root: infocom.congge.model: debugminio:username: miniopwd: miniobucket: testendpoint: http://IP:9000readPath: http://IP:9000

5.2 编码过程

5.2.1 创建一个参数配置类

通过这种方式将配置文件中以minio开头的那些配置加载到spring容器中管理,其他位置使用的时候直接注入即可

@Data
@ConfigurationProperties(prefix = "minio")
@Component
public class MinIOConfigProperties implements Serializable {private String username;private String pwd;private String bucket;private String endpoint;private String readPath;}

5.2.2 创建minio配置类

通过这个全局的配置类,其他需要上传文件的类中直接注入MinioClient即可

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
public class MinIOConfig {@Autowiredprivate MinIOConfigProperties minIOConfigProperties;@Beanpublic MinioClient buildMinioClient() {return MinioClient.builder().credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey()).endpoint(minIOConfigProperties.getEndpoint()).build();}
}

5.2.3 创建minio文件服务类或工具类

在日常开发中,可以自定义一个minio的工具类,使用的时候就比较方便了,下面的代码中列举了常用的一些API操作方法,可以结合实际需要自定义更多的工具方法


import com.congge.config.MinIOConfig;
import com.congge.config.MinIOConfigProperties;
import com.congge.service.MinioFileService;
import io.minio.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;@Slf4j
@Import(MinIOConfig.class)
@Service
public class MinioFileServiceImpl implements MinioFileService {@Autowiredprivate MinioClient minioClient;@Autowiredprivate MinIOConfigProperties minIOConfigProperties;private final static String separator = "/";/*** 下载文件** @param pathUrl 文件全路径* @return 文件流*/@Overridepublic void downLoadFile(String pathUrl, HttpServletResponse response) {String[] pathItems = pathUrl.split("/");String originFileName = pathItems[pathItems.length - 1];String key = pathUrl.replace(minIOConfigProperties.getEndpoint() + "/", "");int index = key.indexOf(separator);//String bucket = key.substring(0,index);String filePath = key.substring(index + 1);InputStream inputStream = null;try {inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minIOConfigProperties.getBucket()).object(filePath).build());response.setHeader("Content-Disposition", "attachment;filename=" + originFileName);response.setContentType("application/force-download");response.setCharacterEncoding("UTF-8");IOUtils.copy(inputStream, response.getOutputStream());System.out.println("下载成功");} catch (Exception e) {log.error("minio down file error.  pathUrl:{}", pathUrl);e.printStackTrace();} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}@Overridepublic String uploadFile(MultipartFile file) throws Exception {String bucketName = minIOConfigProperties.getBucket();String endpoint = minIOConfigProperties.getEndpoint();// 检查存储桶是否已经存在boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());if (isExist) {System.out.println("Bucket already exists.");} else {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}String originalFilename = file.getOriginalFilename();//拼接生成新的UUID形式的文件名String objectName = new SimpleDateFormat("yyyy/MM/dd/").format(new Date()) +UUID.randomUUID().toString().replaceAll("-", "")+ originalFilename.substring(originalFilename.lastIndexOf("."));PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName).bucket(bucketName).contentType(file.getContentType()).stream(file.getInputStream(), file.getSize(), -1).build();minioClient.putObject(objectArgs);//组装桶中文件的访问urlString resUrl = endpoint + "/" + bucketName + "/" + objectName;return resUrl;}/*** 删除文件** @param pathUrl 文件全路径*/@Overridepublic void delete(String pathUrl) {String key = pathUrl.replace(minIOConfigProperties.getEndpoint() + "/", "");int index = key.indexOf(separator);String bucket = key.substring(0, index);String filePath = key.substring(index + 1);// 删除ObjectsRemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build();try {minioClient.removeObject(removeObjectArgs);} catch (Exception e) {log.error("minio remove file error.  pathUrl:{}", pathUrl);e.printStackTrace();}}public List<Bucket> listBuckets()throws Exception {return minioClient.listBuckets();}public boolean bucketExists(String bucketName) throws Exception {boolean flag = minioClient.bucketExists(bucketName);if (flag) {return true;}return false;}@Overridepublic List<String> listBucketNames() throws Exception{List<Bucket> bucketList = listBuckets();List<String> bucketListName = new ArrayList<>();for (Bucket bucket : bucketList) {bucketListName.add(bucket.name());}return bucketListName;}@Overridepublic boolean makeBucket(String bucketName) throws Exception{boolean flag = bucketExists(bucketName);if (!flag) {minioClient.makeBucket(bucketName);return true;} else {return false;}}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic String getObjectUrl(String bucketName, String objectName) throws Exception{boolean flag = bucketExists(bucketName);String url = "";if (flag) {url = minioClient.getObjectUrl(bucketName, objectName);}return url;}public Iterable<Result<Item>> listObjects(String bucketName) throws Exception {boolean flag = bucketExists(bucketName);if (flag) {return minioClient.listObjects(bucketName);}return null;}}

5.2.4 编写测试接口

为了方便测试,下面定义了一个测试接口


import com.congge.service.MinioFileService;
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;@RestController
@Slf4j
public class FileController {@Autowiredprivate MinioFileService minioFileService;/*** 上传文件* @param file* @return* @throws Exception*/@PostMapping("/upload")public String upload(@RequestBody MultipartFile file) throws Exception {String url = minioFileService.uploadFile(file);return "文件上传成功,文件路径:" + url;}/*** 下载文件* @param pathUrl* @param response*/@GetMapping("/download")public void download(@RequestParam("pathUrl") String pathUrl, HttpServletResponse response) {minioFileService.downLoadFile(pathUrl,response);}/*** 列出所有bucket名称* @return* @throws Exception*/@PostMapping("/list/bucket")public List<String> list() throws Exception {return minioFileService.listBucketNames();}/*** 创建bucket* @param bucketName* @return* @throws Exception*/@PostMapping("/create/bucket")public boolean createBucket(@RequestParam("bucketName")String bucketName) throws Exception {return minioFileService.makeBucket(bucketName);}/*** 删除bucket* @param bucketName* @return* @throws Exception*/@PostMapping("/delete/bucket")public boolean deleteBucket(@RequestParam("bucketName")String bucketName) throws Exception {return minioFileService.removeBucket(bucketName);}/*** 列出bucket的所有对象名称* @param bucketName* @return* @throws Exception*/@PostMapping("/list/object_names")public List<String> listObjectNames(@RequestParam("bucketName")String bucketName) throws Exception {return minioFileService.listObjectNames(bucketName);}/*** 删除bucket中的某个对象* @param bucketName* @param objectName* @return* @throws Exception*/@PostMapping("/remove/object")public boolean removeObject(@RequestParam("bucketName")String bucketName,@RequestParam("objectName") String objectName) throws Exception {return minioFileService.removeObject(bucketName, objectName);}/*** 获取文件访问路径* @param bucketName* @param objectName* @return* @throws Exception*/@PostMapping("/get/object/url")public String getObjectUrl(@RequestParam("bucketName")String bucketName, @RequestParam("objectName")String objectName) throws Exception {return minioFileService.getObjectUrl(bucketName, objectName);}}

5.2.5 接口测试

上传文件测试

上传成功后,返回了文件的完整路径,方便后续使用

然后在控制台的test这个bucket中检查是否上传上去了

下载文件测试

使用上一步返回的url,直接调用下载接口,下载完成后可以直接预览

更多的接口有兴趣的同学可以一一尝试下,就不再赘述了。

六、写在文末

本文详细总结了Minio的搭建使用,以及与springboot整合的完整步骤,作为一款适用且轻量级的文件存储服务器,可以私有化部署,也可以很方便进行云上部署、容器化部署,为今后在实际项目中的技术选型提供一个参考,本篇到此结束,感谢观看。

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

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

相关文章

MATLAB 平面拟合并可视化(34)

MATLAB 平面拟合并可视化(34) 一、效果二、代码一、效果 二、代码 % 生成三维点数据 x = rand(100, 1); y = rand(100, 1

Express及mongoose搭建数据库(增删改查)

express是什么&#xff1f; Express.js 是一个基于 Node.js 平台的 Web 应用程序框架&#xff0c;它旨在帮助开发者轻松构建和管理 Web 服务和应用程序。Express 提供了许多强大的功能&#xff0c;使得创建可扩展、灵活且高性能的 Web 应用变得相对容易。 安装Express步骤 确保…

棋牌的电脑计时计费管理系统教程,棋牌灯控管理软件操作教程

一、前言 有的棋牌室在计时的时候&#xff0c;需要使用灯控管理&#xff0c;在开始计时的时候打开灯&#xff0c;在结账后关闭灯&#xff0c;也有的不需要用灯控&#xff0c;只用来计时。 下面以 佳易王棋牌计时计费管理系统软件为例说明&#xff1a; 软件试用版下载或技术支…

LVS+Keepalived集群的介绍和搭建

目录 LVSKeepalived集群的介绍 Keepalived及其工作原理 Keepalived体系主要模块及其作用 一个合格的集群应该具备的特性 健康检查&#xff08;探针&#xff09;的方式 实验&#xff1a;搭建LVSKeepalived集群 实验准备 实验步骤 LVS 部署 配置节点服务器 实验验证 实…

【【UART 传输数据实验】】

UART 传输数据实验 通信方式在日常的应用中一般分为串行通信&#xff08;serial communication&#xff09;和并行通信&#xff08;parallel communication&#xff09;。 我们再来了解下串行通信的特点。串行通信是指数据在一条数据线上&#xff0c;一比特接一比特地按顺序传…

中英购物商城 中英文网店系统怎么选

中英文网店系统能帮助企业将商品卖到不同国家和地区&#xff0c;有效走出国门的工具&#xff0c;在选择中英购物商城时&#xff0c;需要考虑以下几个方面&#xff1a; 1、语言支持&#xff1a;选择一款能够支持中英文双语的购物商城系统是必要的&#xff0c;同时建议选择能确认…

数据结构--图(更新ing~)

树具有灵活性&#xff0c;并且存在许多不同的树的应用&#xff0c;但是就树本身而言有一定的局限性&#xff0c;树只能表示层次关系&#xff0c;比如父子关系。而其他的比如兄弟关系只能够间接表示。 推广--- 图 图形结构中&#xff0c;数据元素之间的关系是任意的。 一、图…

[PTA]分寝室

学校新建了宿舍楼&#xff0c;共有 n 间寝室。等待分配的学生中&#xff0c;有女生 位、男生 位。所有待分配的学生都必须分到一间寝室。所有的寝室都要分出去&#xff0c;最后不能有寝室留空。 现请你写程序完成寝室的自动分配。分配规则如下&#xff1a; 男女生不能混住&…

如何去掉视频中不想要的水印,分享几个视频去水印技巧给你

如何去掉视频中不想要的水印&#xff1f;视频中的水印往往会遮挡画面&#xff0c;降低观看体验。本文将为您介绍三种方法&#xff0c;帮助您轻松去除视频中的水印&#xff0c;以便更好地欣赏和分享视频内容。 视频去水印技巧一&#xff1a;使用水印云 是一款操作简便、功能强大…

【C语言初阶】数组

目录 一、一维数组的创建和初始化 1.1 数组的创建 1.2 数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 二、二维数组的创建和初始化 2.1 二维数组的创建 2.2 二维数组的初始化 2.3 二维数组的使用 2.4 二维数组在内存中的存储 三、数组越界 四、数组作…

智能高效的Go开发工具GoLand v2023.3发布,支持AI辅助编码!

GoLand 使 Go 代码的阅读、编写和更改变得非常容易。即时错误检测和修复建议&#xff0c;通过一步撤消快速安全重构&#xff0c;智能代码完成&#xff0c;死代码检测和文档提示帮助所有 Go 开发人员&#xff0c;从新手到经验丰富的专业人士&#xff0c;创建快速、高效、和可靠的…

图片速览 OOD用于零样本 OOD 检测的 CLIPN:教 CLIP 说不

PAPERCODEhttps://arxiv.org/pdf/2308.12213v2.pdfhttps://github.com/xmed-lab/clipn 文章创新 以往由CLIP驱动的零样本OOD检测方法&#xff0c;只需要ID的类名&#xff0c;受到的关注较少。 本文提出了一种新的方法&#xff0c;即CLIP说“不”&#xff08;CLIPN&#xff09;…

计算机基础,以及实施运维工程师介绍

目录 一.实施&#xff0c;运维工程师介绍 1.什么是实施工程师&#xff1f; 实施工程师职责 2.什么是运维工程师&#xff1f; 运维工程师职责 3.实施运维需要的技术 数据库 操作系统 网络 服务器 软件 硬件 网络 二.计算机介绍 CPU 存储器 io 总线 主板 三.操…

计算机毕业设计—基于Koa+vue的高校宿舍管理系统宿舍可视化系统

项目介绍 项目背景 随着科技的发展&#xff0c;智能化管理越来越重要。大学生在宿舍的时间超过了1/3&#xff0c;因此良好的宿舍管理对学生的生活和学习极为关键。学生宿舍管理系统能够合理安排新生分配宿舍&#xff0c;不浪费公共资源&#xff0c;减轻学校管理压力&#xff…

你了解Redis中的跳跃表吗?

跳跃表的基本内容&#xff1a; 对于一个有序序列&#xff0c;链表相对于数组来说&#xff0c;删除和插入的效率要快很多&#xff0c;只需要改变指针的指向&#xff0c;但是在查找的时候&#xff0c;数组就要更占优势一些&#xff0c;可以随机访问&#xff0c;然而链表需要从头…

oracle与gbase8s迁移数据类型对照

声明&#xff1a;以下为笔者阅读gbase官方文档和oracle官方文档的理解&#xff0c;如有错误&#xff0c;敬请指正。oracle与gbase8s迁移数据类型对照及举例说明 最终结论&#xff1a;oracle与gbase8s数据类型对应关系关于单精度与双精度的区别关于定点与浮点定义的区别精度的定…

[报错已解决]得到一个不期待的值added_cond_kwargs,图生图和文生图的pipline是不同的

报错内容 得到一个不期待的值added_cond_kwargs 问题原因 对照下图&#xff0c;做测试unet_2d_condition.py里面UNet2dConditionModel类的forward输入 而StableDiffusionPipline&#xff08;文生图t2i&#xff09;的self.unet输入里面多了一个added_cond_kwargs需要写 从下图可…

函数torch.bincount( )的用法

torch.bincount()函数是PyTorch中的一个函数&#xff0c;用于计算一维整数张量中每个非负整数值出现的频次 函数的用法 &#xff1a; torch.bincount(input, weightsNone, minlength0) → Tensor 参数&#xff1a; input&#xff1a;输入的一维整数张量weights&#xff08;…

机器学习——支持向量机

目录 一、基于最大间隔分隔数据 二、寻找最大间隔 1. 最大间隔 2. 拉格朗日乘子法 3. 对偶问题 三、SMO高效优化算法 四、软间隔 五、SMO算法实现 1. 简化版SMO算法 2. 完整版SMO算法 3. 可视化决策结果 六、核函数 1. 线性不可分——高维可分 2. 核函数 …

设计模式 原型模式 与 Spring 原型模式源码解析(包含Bean的创建过程)

原型模式 原型模式(Prototype模式)是指&#xff1a;用原型实例指定创建对象的种类&#xff0c;并且通过拷贝这些原型&#xff0c;创建新的对象。 原型模式是一种创建型设计模式&#xff0c;允许一个对象再创建另外一个可定制的对象&#xff0c;无需知道如何创建的细节。 工作原…