springboot 对接 minio 分布式文件系统

1. minio介绍

Minio 是一个基于Go语言的对象存储服务。它实现了大部分亚马逊S3云存储服务接口,可以看做是是S3的开源版本,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。区别于分布式存储系统,minio的特色在于简单、轻量级,对开发者友好,认为存储应该是一个开发问题而不是一个运维问题。


2. minio下载地址

下载

3. liunx minio文件授权

chomd +x minio

4. 编写启动minio shell文件

vi run.sh

#!/bin/bash
#web管理界面登录用户
export MINIO_ROOT_USER=minio
#web管理界面登录密码
export MINIO_ROOT_PASSWORD=minio
#生成共享链接时,需要配置,否则是本地地址127.0.0.1,有地址的可以修改为自己地址
export MINIO_SERVER_URL=http://IP:9002
# nohup启动服务 指定文件存放路径 /root/data 还有设置日志文件路径 /root/minio/log
nohup ./minio server --address :9002 --console-address :9001 /root/data/minio > /root/logs/minio.log 2>&1 &

5. 赋权限给予shell文件run.sh文件

 chmod u+x run.sh

.

6. 启动minio服务,执行sh文件

bash run.sh

7. 查看日志,我们在4的时候最后一条上有配置log地址

tail -f /root/logs/minio.log

8. 浏览器访问minio界面,并且输入在第四步配置的账号密码

9. 接下来我们可以创建一个我们作为测试的文件桶

 

 10. 当我们创建好桶之后,我们可以前往查看是否存在

11. 点击桶进入,手动测试上传文件

12. 上传文件之后我们可以选择某一个文件进行下载或者链接共享,链接共享默认时间为7天

13. 当我们点击共享时,会出现一个共享链接,我们可以直接在浏览器内查看相对应的文件

14. springboot 对接minio,加入POM文件

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

15. 配置application文件

生成请求账号密码

minio:endpoint: http://IP:9002accessKey: bjdZxvMDxAzYETgYn0aY 配置账号secretKey: uk7srkLHsYkwzvTYVzDBtwzlXz5fxsoMmNpbb3SN 配置密码bucketName: test 桶名称-默认

16.springboot 工具类

package com.project.google.util;/*** @Description: TODO* @Author xgp* @Date 2023/8/7 8:05* @PackageName:com.project.google.util* @ClassName: MinioTemplate* @Version 1.0*/import io.minio.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;/*** Minio 基础操作类** @author: zhanghuaiyu* @since 2021-01-22 16:27*/
@Configuration
public class MinioTemplate implements InitializingBean {private MinioClient minioClient;@Value("${minio.endpoint}")private String url;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Overridepublic void afterPropertiesSet() {Assert.hasText(url, "Minio url 为空");Assert.hasText(accessKey, "Minio accessKey为空");Assert.hasText(secretKey, "Minio secretKey为空");this.minioClient = new MinioClient(url, accessKey, secretKey);}/*** 创建bucket* setBucketPolicy 设置权限才可以预览** @param bucketName bucket名称*/@SneakyThrowspublic Boolean createBucket(String bucketName) {if (!bucketExists(bucketName)) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());StringBuilder builder = new StringBuilder();builder.append("{\n");builder.append("    \"Statement\": [\n");builder.append("        {\n");builder.append("            \"Action\": [\n");builder.append("                \"s3:GetBucketLocation\",\n");builder.append("                \"s3:ListBucket\"\n");builder.append("            ],\n");builder.append("            \"Effect\": \"Allow\",\n");builder.append("            \"Principal\": \"*\",\n");builder.append("            \"Resource\": \"arn:aws:s3:::bucketname\"\n");builder.append("        },\n");builder.append("        {\n");builder.append("            \"Action\": \"s3:GetObject\",\n");builder.append("            \"Effect\": \"Allow\",\n");builder.append("            \"Principal\": \"*\",\n");builder.append("            \"Resource\": \"arn:aws:s3:::my-bucketname/*.*\"\n");builder.append("        }\n");builder.append("    ],\n");builder.append("    \"Version\": \"2012-10-17\"\n");builder.append("}\n");minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(builder.toString().replace("bucketname", bucketName)).build());return true;} else {return false;}}/*** 获取全部bucket* <p>* https://docs.minio.io/cn/java-client-api-reference.html#listBuckets*/@SneakyThrowspublic List<Bucket> getAllBuckets() {return minioClient.listBuckets();}/*** 根据bucketName获取信息** @param bucketName bucket名称*/@SneakyThrowspublic Optional<Bucket> getBucket(String bucketName) {return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();}/*** 根据bucketName删除信息** @param bucketName bucket名称*/@SneakyThrowspublic void removeBucket(String bucketName) {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}/*** 根据文件前置查询文件** @param bucketName bucket名称* @param prefix     前缀* @param recursive  是否递归查询* @return MinioItem 列表*/@SneakyThrowspublic List getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {List<Item> list = new ArrayList<>();Iterable<Result<Item>> objectsIterator = minioClient.listObjects(bucketName, prefix, recursive);if (objectsIterator != null) {Iterator<Result<Item>> iterator = objectsIterator.iterator();if (iterator != null) {while (iterator.hasNext()) {Result<Item> result = iterator.next();Item item = result.get();list.add(item);}}}return list;}/*** 获取文件外链** @param bucketName bucket名称* @param objectName 文件名称* @param expires    过期时间 <=7* @return url*/@SneakyThrowspublic String getObjectUrl(String bucketName, String objectName, Integer expires) {return minioClient.presignedGetObject(bucketName, objectName, expires);}/*** 获取文件路径** @param bucketName* @param fileName* @return*/@SneakyThrowspublic String getObjectUrl(String bucketName, String fileName) {return minioClient.getObjectUrl(bucketName, fileName);}/*** 获取文件** @param bucketName bucket名称* @param objectName 文件名称* @return 二进制流*/@SneakyThrowspublic InputStream getObject(String bucketName, String objectName) {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** 获取文件** @param bucketName* @param objectName* @return*/@SneakyThrowspublic ObjectStat statObject(String bucketName, String objectName) {return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject*/public String putObject(String bucketName, String objectName, MultipartFile file) throws Exception {if (!this.bucketExists(bucketName)) {this.createBucket(bucketName);}minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(file.getInputStream(), file.getSize(), PutObjectArgs.MIN_MULTIPART_SIZE).contentType(file.getContentType()).build());return bucketName;}/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream     文件流* @param size       大小* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject*/public void putObject(String bucketName, String objectName, InputStream stream, long size) throws Exception {minioClient.putObject(bucketName, objectName, stream, new PutObjectOptions(stream.available(), -1));}/*** 获取文件信息, 如果抛出异常则说明文件不存在** @param bucketName bucket名称* @param objectName 文件名称* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject*/public ObjectStat getObjectInfo(String bucketName, String objectName) throws Exception {return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** 删除文件** @param bucketName bucket名称* @param objectName 文件名称* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject*/public void removeObject(String bucketName, String objectName) throws Exception {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** 批量删除文件夹内所有文件** @param bucketName bucket名称* @param objectName 文件名称* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject*/public void removeObjects(String bucketName, String objectName) throws Exception {List<Item> list = getAllObjectsByPrefix(bucketName, objectName, false);for (Item item : list) {removeObject(bucketName, item.objectName());}}@SneakyThrowspublic boolean bucketExists(String bucketName) {return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}/*** 文件下载** @param response* @param bucket* @param objectName* @param outName* @throws Exception*/public void download(HttpServletResponse response, String bucket, String objectName, String outName) throws Exception {ObjectStat stat = this.statObject(bucket, objectName);response.setContentType(stat.contentType());response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(outName, "UTF-8"));response.setHeader("FileName", URLEncoder.encode(outName, "UTF-8"));InputStream in = this.getObject(bucket, objectName);IOUtils.copy(in, response.getOutputStream());in.close();}/*** 合并分片文件到指定目录** @param bucket* @param fileName* @param sources* @return* @throws Exception*/public ObjectWriteResponse composeObject(String bucket, String fileName, List<ComposeSource> sources) throws Exception {ObjectWriteResponse response = minioClient.composeObject(ComposeObjectArgs.builder().bucket(bucket).object(fileName).sources(sources).build());return response;}
}

 17.请求测试controller方法

package com.project.google.controller;import afu.org.checkerframework.checker.oigj.qual.O;
import com.project.google.util.MinioTemplate;
import io.minio.messages.Bucket;
import org.apache.commons.io.IOUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;
import java.util.*;/*** @Description: TODO* @Author xgp* @Date 2023/8/7 8:35* @PackageName:com.project.google.controller* @ClassName: TbMinioController* @Version 1.0*/
@RestController
public class TbMinioController {@Autowiredprivate MinioTemplate minioTemplate;//创建新的桶@GetMapping("createBucket")public Object createBucket(String bucketName){return minioTemplate.createBucket(bucketName);}//获取对应桶信息@GetMapping("getList")public Object getList(String bucketName){Bucket bucket = minioTemplate.getBucket(bucketName).get();Map<String,Object> map = new HashMap<>();map.put("name",bucket.name());map.put("createDate",bucket.creationDate());return map;}//获取所有桶信息@GetMapping("getAll")public Object getAll(){List<Map> list = new ArrayList<>();List<Bucket> buckets = minioTemplate.getAllBuckets();buckets.stream().forEach(item -> {Map<String,Object> map = new HashMap<>();map.put("name",item.name());map.put("createDate",item.creationDate());list.add(map);});return list;}/**上传文件到对应桶里,如果你想放入指定文件夹,传入文件名前面带上文件夹名称及路径,比如 test文件夹就- test/文件名,依次类推*/@PostMapping("uploadFile")public Object uploadFile(@RequestParam("file") MultipartFile file) throws Exception {/**文件夹属性,可加载文件前方*/return minioTemplate.putObject("test","uu/" + file.getOriginalFilename(),file);}/**获取图片信息,二进制数据转换为图片呈现*/@GetMapping(value = "getFile", produces = MediaType.IMAGE_JPEG_VALUE)public byte[] getFile(@RequestParam("bucketName") String bucketName,@RequestParam("objectName") String objectName) throws IOException {InputStream stream = minioTemplate.getObject(bucketName, objectName);byte[] bytes = IOUtils.toByteArray(stream);return bytes;}/**获取图片分享链接,expires为过期时间,可为小于等于7*/@GetMapping(value = "getObjectUrl")public String getObjectUrl(@RequestParam("bucketName") String bucketName,@RequestParam("objectName") String objectName) throws IOException {return minioTemplate.getObjectUrl(bucketName, objectName, 1);}}

18.接口测试

18.1 查询test bucket信息

 

18.2 获取所有bucket信息

18.3 上传文件,我这边是通过apipox进行测试

18.4 查看图片信息

18.5 生成共享链接

到此,整个对接过程就已经差不多了,其他扩展功能,如有需要,可以咨询这边,给出解答或者思路。

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

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

相关文章

Qt能跨多少个平台?Qt能支持多少个平台?

2023年8月5日&#xff0c;周日下午 目录 Qt所支持的平台更多关于Qt支持的信息 Qt所支持的平台 图中显示的平台都支持。 想要更详细的平台支持信息可以查看&#xff1a;Supported Platforms | Qt 5.15 更多关于Qt支持的信息 Qt - 支持的平台及语言

MongoDB 入门

1.1 数据库管理系统 在了解MongoDB之前需要先了解先数据库管理系统 1.1.1 什么是数据&#xff1f; 数据&#xff08;英语&#xff1a;data&#xff09;&#xff0c;是指未经过处理的原始记录。 一般而言&#xff0c;数据缺乏组织及分类&#xff0c;无法明确的表达事物代表的意…

服务器中了malox勒索病毒后怎么办怎么解决,malox勒索病毒解密数据恢复

服务器遭受Malox勒索病毒攻击后&#xff0c;快速解密并恢复数据至关重要&#xff0c;以便减少更大的经济损失。近期&#xff0c;新的一波malox勒索病毒正在肆虐&#xff0c;我们收到很多企业的求助&#xff0c;企业的服务器数据库遭到了malox勒索病毒攻击&#xff0c;导致系统内…

如何使用win10专业版系统自带远程桌面公司内网电脑,从而实现居家办公?

使用win10专业版自带远程桌面公司内网电脑 文章目录 使用win10专业版自带远程桌面公司内网电脑 在现代社会中&#xff0c;各类电子硬件已经遍布我们身边&#xff0c;除了应用在个人娱乐场景的消费类电子产品外&#xff0c;各项工作也离不开电脑的帮助&#xff0c;特别是涉及到数…

09. Docker Compose

目录 1、前言 2、安装Docker Compose 2.1、Docker Compose版本 2.2、下载安装 3、初试Docker Compose 3.1、传统方案部署应用 3.2、使用编排部署应用 3.3、其他命令 3.3.1、ps 3.3.2、images 3.3.3、depends_on 3.3.4、scale 4、小结 1、前言 随着应用架构的不段…

Python爬虫异常处理心得:应对网络故障和资源消耗

作为一名专业的爬虫代理&#xff0c;我知道在爬取数据的过程中&#xff0c;遇到网络故障和资源消耗问题是再正常不过了。今天&#xff0c;我将与大家分享一些关于如何处理这些异常情况的心得和技巧。不论你是在处理网络不稳定还是资源消耗过大的问题&#xff0c;这些技巧能够帮…

uniapp微信小程序 401时重复弹出登录弹框问题

APP.vue 登陆成功后&#xff0c;保存登陆信息 if (res.code 200) {uni.setStorageSync(loginResult, res)uni.setStorageSync(token, res.token);uni.setStorageSync(login,false);uni.navigateTo({url: "/pages/learning/learning"}) }退出登录 toLogout: func…

离线数仓-项目介绍

1. 系统架构 2. 介绍流程 公司的困难数据的来源 业务日志 Flume采集日志数据 选型 ETL flume内存不够&#xff0c;通过ganglia监控器发现 提高吞吐量&#xff0c;batchSize kafka 高效读写 提高吞吐量 kafka挂了 kafka丢数问题 数据重复问题 数据乱序问题 消费策略…

深度学习部署:FastDeploy部署教程(CSharp版本)

FastDeploy部署教程(CSharp版本) 1. FastDeploy介绍 FastDeploy是一款全场景、易用灵活、极致高效的AI推理部署工具&#xff0c; 支持云边端部署。提供超过 &#x1f525;160 Text&#xff0c;Vision&#xff0c; Speech和跨模态模型&#x1f4e6;开箱即用的部署体验&#xf…

消息队列常见问题(1)-如何保障不丢消息

目录 1. 为什么消息队列会丢消息&#xff1f; 2. 怎么保障消息可靠传递&#xff1f; 2.1 生产者不丢消息 2.2 服务端不丢消息 2.3 消费者不丢消息 3. 消息丢失如何快速止损&#xff1f; 3.1 完善监控 3.2 完善止损工具 1. 为什么消息队列会丢消息&#xff1f; 现在主流…

支付模块功能实现(小兔鲜儿)【Vue3】

支付 渲染基础数据 支付页有俩个关键数据&#xff0c;一个是要支付的钱数&#xff0c;一个是倒计时数据&#xff08;超时不支付商品释放&#xff09; 准备接口 import request from /utils/httpexport const getOrderAPI (id) > {return request({url: /member/order/$…

PyTorch深度学习实战(10)——过拟合及其解决方法

PyTorch深度学习实战&#xff08;10&#xff09;——过拟合及其解决方法 0. 前言1. 过拟合基本概念2. 添加 Dropout 解决过拟合3. 使用正则化解决过拟合3.1 L1 正则化3.2 L2 正则化 4. 学习率衰减小结系列链接 0. 前言 过拟合 (Overfitting) 是指在机器学习中&#xff0c;模型…

android studio内存分析之Memory profiler的使用

目录 Android Studio中内存分析工具Memory profiler的使用1. 打开Memory Profiler2. 工具使用3. 内存选项说明4. 内存性能分析器概览5. 内存计算方式6. 查看内存分配7. 捕获java/kotlin方式查看内存分配8. 堆转储文件导入和导出 内存性能分析器中的泄漏检测 Android Studio中内…

【ArcGIS Pro二次开发】(58):数据的本地化存储

在做村规工具的过程中&#xff0c;需要设置一些参数&#xff0c;比如说导图的DPI&#xff0c;需要导出的图名等等。 每次导图前都需要设置参数&#xff0c;虽然有默认值&#xff0c;但还是需要不时的修改。 在使用的过程中&#xff0c;可能会有一些常用的参数&#xff0c;希望…

Sentinel 2.0 微服务零信任的探索与实践

作者&#xff1a;涯客、十眠 从古典朴素的安全哲学谈起 网络安全现状 现在最常见的企业网络安全架构便是在企业网络边界处做安全防护&#xff0c;而在企业网络内部不做安全防范。这确实为企业的安全建设省了成本也为企业提供了一定的防护能力。但是这类比于现实情况的一个小…

单通道 6GSPS 16位采样DAC子卡模块--【资料下载】

FMC147是一款单通道6.4GSPS&#xff08;或者配置成2通道3.2GSPS&#xff09;采样率的12位AD采集、单通道6GSPS&#xff08;或配置成2通道3GSPS&#xff09;采样率16位DA输出子卡模块&#xff0c;该板卡为FMC标准&#xff0c;符合VITA57.4规范&#xff0c;该模块可以作为一个理想…

力扣:54. 螺旋矩阵(Python3)

题目&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣 示例&#xff1a; 示例 1&#xff1a; 输入&#xff1a;matrix [[1,…

手机便签内容不见了怎么恢复正常?

在日常生活和工作中&#xff0c;很多人都需要随手记录事情&#xff0c;例如家庭琐事、孩子相关的事情、指定时间需要完成的工作任务、会议安排等。当我们需要随时随地记录事情的时候&#xff0c;手机便签应用就是非常不多的选择&#xff0c;我们直接打开手机上的便签APP就可以新…

安全基础 --- https详解 + 数组(js)

CIA三属性&#xff1a;完整性&#xff08;Confidentiality&#xff09;、保密性&#xff08;Integrity&#xff09;、可用性&#xff08;Availability&#xff09;&#xff0c;也称信息安全三要素。 https 核心技术&#xff1a;用非对称加密传输对称加密的密钥&#xff0c;然后…

【多线程】synchronized 原理

1. 写在前面 本章节主要介绍 synchronized 的一些内部优化机制&#xff0c;这些机制存在的目的呢就是让 synchronized 这把锁更高效更好用&#xff01; 2. 锁升级/锁膨胀 JVM 将 synchronized 锁分为以下四种状态&#xff1a; 无锁&#xff0c;偏向锁&#xff0c;轻量级锁&…