SpringBoot 整合 Minio

官网:
MinIO 是一个基于 Go 实现的高性能、兼容 S3 协议的对象存储。它采用 GNU AGPL v3 开源协议,项目地址是 https://github.com/minio/minio 。

它适合存储海量的非结构化的数据,例如说图片、音频、视频等常见文件,备份数据、容器、虚拟机镜像等等,小到 1 KB,大到 5 TB 都可以支持。

添加依赖

<properties><java.version>1.8</java.version><minio.version>8.4.3</minio.version>
</properties><dependencies><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>${minio.version}</version></dependency>
</dependencies>

Minio 配置类

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MinioConfig {@Value("${minio.url}")private String url;@Value("${minio.access-key}")private String accessKey;@Value("${minio.secret-key}")private String secretKey;@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();}
}

application.yml 配置文件

minio:url: http://127.0.0.1:9000accessKey: 45wsHpkAIWfhghSs11XsecretKey: D9fghfg6sahgufghfgdOYrwqHqocfgh2njhfgh

MinioTemplate.java 封装方法

封装常用的上传(多文件上传、单文件上传)、获取链接、删除、下载方法,方便使用。

import com.ufan.mall.model.FileVo;
import io.minio.*;
import io.minio.http.Method;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;/*** @ClassName:MinioTemplate.java* @Description:MinioTemplate* @Author:tanyp* @Date:2023/07/27 15:49**/
@Slf4j
@Component
public class MinioTemplate {@Autowiredprivate MinioClient client;/*** @MonthName:upload* @Description: 上传文件* @Author:tanyp* @Date:2023/07/27 15:52* @Param: [file, bucketName]* @return:void**/public FileVo upload(MultipartFile file, String bucketName) {try {createBucket(bucketName);String oldName = file.getOriginalFilename();String fileName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + UuidUtil.getRandomPwd(15) + oldName.substring(oldName.lastIndexOf("."));client.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(file.getInputStream(), file.getSize(), 0).contentType(file.getContentType()).build());String url = this.getObjUrl(bucketName, fileName);return FileVo.builder().oldFileName(oldName).newFileName(fileName).fileUrl(url.substring(0, url.indexOf("?"))).build();} catch (Exception e) {log.error("上传文件出错:{}", e);return null;}}/*** @MonthName:uploads* @Description: 上传多个文件* @Author:tanyp* @Date:2023/07/27 15:52* @Param: [file, bucketName]* @return:void**/public List<FileVo> uploads(List<MultipartFile> files, String bucketName) {try {List<FileVo> list = new ArrayList<>();createBucket(bucketName);for (MultipartFile file : files) {String oldName = file.getOriginalFilename();String fileName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + UuidUtil.getRandomPwd(15) + oldName.substring(oldName.lastIndexOf("."));client.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(file.getInputStream(), file.getSize(), 0).contentType(file.getContentType()).build());String url = this.getObjUrl(bucketName, fileName);list.add(FileVo.builder().oldFileName(oldName).newFileName(fileName).fileUrl(url.substring(0, url.indexOf("?"))).build());}return list;} catch (Exception e) {log.error("上传文件出错:{}", e);return null;}}/*** @MonthName:download* @Description: 下载文件* @Author:tanyp* @Date:2023/07/27 15:54* @Param: [bucketName, fileName]* @return:void**/public void download(String bucketName, String fileName) throws Exception {client.downloadObject(DownloadObjectArgs.builder().bucket(bucketName).filename(fileName).build());}/*** @MonthName:getObjUrl* @Description: 获取文件链接* @Author:tanyp* @Date:2023/07/27 15:55* @Param: [bucketName, fileName]* @return:java.lang.String**/public String getObjUrl(String bucketName, String fileName) throws Exception {return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).method(Method.GET).expiry(30, TimeUnit.SECONDS).build());}/*** @MonthName:delete* @Description: 删除文件* @Author:tanyp* @Date:2023/5/26 15:56* @Param: [bucketName, fileName]* @return:void**/public void delete(String bucketName, String fileName) throws Exception {client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());}@SneakyThrowspublic void createBucket(String bucketName) {if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());String sb = "{\"Version\": \"2012-10-17\",\"Statement\": [{\"Effect\": \"Allow\",\"Principal\": {\"AWS\": [\"*\"]},\"Action\": [\"s3:GetBucketLocation\"],\"Resource\": [\"arn:aws:s3:::" + bucketName + "\"]},{\"Effect\": \"Allow\",\"Principal\": {\"AWS\": [\"*\"]},\"Action\": [\"s3:ListBucket\"],\"Resource\": [\"arn:aws:s3:::" + bucketName + "\"],\"Condition\": {\"StringEquals\": {\"s3:prefix\": [\"*\"]}}},{\"Effect\": \"Allow\",\"Principal\": {\"AWS\": [\"*\"]},\"Action\": [\"s3:GetObject\"],\"Resource\": [\"arn:aws:s3:::" + bucketName + "/**\"]}]}";client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(sb).build());}}}

FileVo.java 实体类

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FileVo {/*** 原文件名*/private String oldFileName;/*** 新文件名*/private String newFileName;/*** 文件路径*/private String fileUrl;}

动态创建 Bucket

如何设置桶的权限?

在MinIO中,可以通过设置桶策略来控制桶的访问权限。桶策略是一个JSON格式的文本文件,用于指定哪些实体(用户、组或IP地址)可以执行哪些操作(读、写、列举等)。

MinIO桶策略的基本结构如下所示:

{"Version": "2012-10-17","Statement": [{"Action": ["action1", "action2", ...],"Effect": "Allow|Deny","Principal": {"AWS": ["arn:aws:iam::account-id:user/user-name"]},"Resource": ["arn:aws:s3:::bucket-name/object-prefix", ...]},...]
}

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

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

相关文章

mysql sql 语句sum求和嵌套数学表达式

今天有个需求, 已减高度 高度 x 单双开(单开1 双开2) x 2,要直接写在sql语句中。 表字段 包含 高度 和 单双开字段 值是字符串 (双开 左单开 右单开) -- 已减高度 2 * 单双开 * 高度 sum( -- 求和 表达式 已减高度 2 * 单双开 * 高度 t_cloth.hegiht * 2 * (case WHEN l…

rust from_utf8_lossy怎么使用?

from_utf8_lossy 是Rust标准库中的一个方法&#xff0c;用于将字节序列解码为UTF-8字符串。它的作用是尽可能地将无效的字节序列转换为有效的Unicode字符&#xff0c;以便进行后续处理。 以下是使用 from_utf8_lossy 方法的示例代码&#xff1a; fn main() {let bytes b"…

QT充当客户端模拟浏览器等第三方客户端对https进行双向验证

在 ssl单向证书和双向证书校验测试及搭建流程 文章中&#xff0c;已经做了基于https的单向认证和双向认证&#xff0c;&#xff0c;&#xff0c; 在进行双向认证时&#xff0c;采用的是curl工具或浏览器充当客户端去验证。 此次采用QT提供的接口去开发客户端向服务器发送请求&a…

【雕爷学编程】 MicroPython动手做(35)——体验小游戏

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

解决el-dialog弹出时,页面抖动,右侧会缩小的问题(即滚动条被遮罩层覆盖的问题)

问题描述&#xff1a; 在弹出el-dialog时&#xff0c;会发现弹出框弹出时&#xff0c;页面会抖动&#xff0c;滚动条被遮罩层覆盖直接没有滚动条了&#xff0c;导致页面缩小了几个像素点&#xff08;滚动条的宽度&#xff09;&#xff1b;体验感不好&#xff0c;会影响到页面的…

6G内存运行Llama2-Chinese-7B-chat模型

6G内存运行Llama2-Chinese-7B-chat模型 Llama2-Chinese中文社区 第一步&#xff1a; 从huggingface下载 Llama2-Chinese-7b-Chat-GGML模型放到本地的某一目录。 第二步&#xff1a; 执行python程序 git clone https://github.com/Rayrtfr/llama2-webui.gitcd llama2-web…

嘉立创EDA画爱心

需要用&#xff1a;折线(L)&#xff0c;两点圆弧&#xff0c;三点圆弧(A)&#xff0c;园形(U)等功能 如下就是画出的图形 2D 3D 去除丝印pcb 2d 3d

【雕爷学编程】 MicroPython动手做(34)——通用传感器的综合运用2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

数据库导出Excel格式的表结构

数据库导出Excel格式的表结构 你是否遇到到导出数据库里面的表结构&#xff0c;包含字段名称、类型、长度、小数、默认值、字段描述之类的需求&#xff1b;当我们去navcat里面找时发现没有&#xff0c;因为navcat没有提供这一功能&#xff0c;他只可以导出表结构的sql&#xff…

JDK8:Optional详解与源码分析,如何优雅的处理空指针

文章目录 一、Optional概述1、烦人的NullPointerException2、Optional简介 二、Optional使用1、创建Optional对象2、isPresent()与ifPresent()应用&源码解析3、get()应用&源码解析4、orElseThrow()应用&源码解析5、map()应用&源码解析6、flatMap()应用&源码…

《练习100》31~35

题目31 # press any key to change color,do you want to try it. Please hurry up!# 第一种使用颜色配置输出 # 向终端输出彩色字符&#xff0c;色彩的设置由目标终端文字系统和转义字符控制&#xff0c;与具体的编程语言无关 # 参数名称 参数值 # 文字效果 0&#xff1a;终端…

利用ChatGPT制作行业应用:哪些行业最受益

引言 随着人工智能技术的快速发展&#xff0c;ChatGPT&#xff08;Chat Generative Pre-trained Transformer&#xff09;成为了一种引人注目的工具&#xff0c;它能够生成自然流畅的对话内容。这种技术不仅在娱乐领域有着广泛的应用&#xff0c;还可以在各个行业中发挥重要作…

数据可视化(5)热力图及箱型图

1.热力图 #基本热力图 #imshow&#xff08;x&#xff09; #x&#xff0c;数据 x[[1,2],[3,4],[5,6],[7,8],[9,10]] plt.imshow(x) plt.show() #使用热力图分析学生的成绩 dfpd.read_excel(学生成绩表.xlsx) #:表示行号 截取数学到英语的列数 xdf.loc[:,"数学":英语].…

《金融数据保护治理白皮书》发布(137页)

温馨提示&#xff1a;文末附完整PDF下载链接 导读 目前业界已出台数据保护方面的治理模型&#xff0c;但围绕金融数据保护治理的实践指导等尚不成熟&#xff0c;本课题围绕数据保护治理的金融实践、发展现状&#xff0c;探索和标准化相关能力要求&#xff0c;归纳总结相关建…

QT ubuntu下开发视频播放 FFmpeg

ubuntu 安装FFmpeg T113VideoDemo.pro #------------------------------------------------- # # Project created by QtCreator 2023-07-28T11:45:22 # #-------------------------------------------------QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widget…

docker更换数据存储路径

1. 先停掉docker服务 sudo systemctl stop docker 可能会出现的问题&#xff1a; 这样会导致docker关闭失败,解决办法&#xff1a;systemctl stop docker.socket 确保docker关闭: 2.备份现在的 Docker 数据存储目录 /var/lib/docker(默认路径) mv /var/lib/docker /var/lib/…

Meta开源Llama 2免费大语言模型,媲美ChatGPT,可在线试玩

Llama 2是Llama 1模型的升级版本,引入了一系列预训练和微调 LLM,参数量范围从7B到70B (7B、13B、70B)。其预训练模型比 Llama 1模型有了显著改进,包括训练数据的总词元数增加了 40%、上下文长度更长 (4k 词元),以及利用了分组查询注意力机制来加速 70B模型的推理! 但最激动…

快速远程桌面控制公司电脑远程办公

文章目录 第一步第二步第三步 远程办公的概念很早就被提出来&#xff0c;但似乎并没有多少项目普及落实到实际应用层面&#xff0c;至少在前几年&#xff0c;远程办公距离我们仍然很遥远。但2019年末突如其来的疫情&#xff0c;着实打了大家一个措手不及。尽管国内最初的大面积…

vue的生命周期

什么是生命周期 Vue 实例从创建到销毁的过程就是生命周期。从开始创建&#xff0c;初始化数据&#xff0c;编译模板&#xff0c;挂载 Dom 到渲染&#xff0c;更新到渲染&#xff0c;销毁等一系列过程&#xff0c;称之为生命周期 Vue生命周期共有8个阶段&#xff0c;分别为&am…

【Leetcode】(自食用)找到消失的数字

step by step. 题目&#xff1a; 给你一个含 n 个整数的数组 nums &#xff0c;其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字&#xff0c;并以数组的形式返回结果。 示例 1&#xff1a; 输入&#xff1a;nums [4,3,2,7,8,2,3,1] 输…