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

SpringBoot + minio实现分片上传、秒传、续传

什么是minio

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

引用官网:

MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储。它与Amazon S3云存储服务兼容。使用MinIO构建用于机器学习,分析和应用程序数据工作负载的高性能基础架构。

官网地址:

https://min.io/

文档地址:

https://docs.min.io/

一. 使用docker 搭建minio 服务

GNU / Linux和macOS

docker run -p 9000:9000 \   --name minio1 \   -v /mnt/data:/data \   -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \   -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \   minio/minio server /data

windows

docker run -p 9000:9000 \   --name minio1 \   -v D:\data:/data \   -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \   -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \   minio/minio server /data

  • MINIO_ROOT_USER:为用户key

  • MINIO_ROOT_PASSWORD:为用户密钥

以上搭建的都是单机版的。想要了解分布式 的方式请查看官网文档。

图片

这就是在win的docker上运行的。

更多开源项目:https://www.yoodb.com/projects/springboot-user-manger.html

当启动后在浏览器访问http://localhost:9000就可以访问minio的图形化界面了,如图所示:

图片

图片

二. 下面开始搭建springboot 环境

初始化一个springboot项目大家都会,这里不多做介绍。

主要是介绍需要引入的依赖:

<!-- thymeleaf模板渲染引擎-->  <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-thymeleaf</artifactId>        </dependency><!-- 操作minio的java客户端-->         <dependency>            <groupId>io.minio</groupId>            <artifactId>minio</artifactId>            <version>8.2.1</version>        </dependency><!-- lombok插件-->         <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>            <optional>true</optional>        </dependency>

依赖可以官方文档里找:https://docs.min.io/docs/java-client-quickstart-guide.html

下面介绍配置文件:

spring:   servlet:     multipart:       max-file-size: 10MB       max-request-size: 10MB *#minio配置*   minio:     access-key: AKIAIOSFODNN7EXAMPLE      *#key就是docker初始化是设置的,密钥相同*     secret-key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY     url: http://localhost:9000     bucket-name: wdhcr   thymeleaf:     cache: false

创建minio的配置类:

`@Configuration
@ConfigurationProperties(prefix = “spring.minio”)
@Data
public class MinioConfiguration {
    private String accessKey;

private String secretKey;

private String url;

private String bucketName;

@Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(url)
                .credentials(accessKey, secretKey)
                .build();
    }
}
`

使用配置属性绑定进行参数绑定,并初始化一个minio client对象放入容器中。

下面就是我封装的minio client 操作minio的简单方法的组件。

`@Component
public class MinioComp {

@Autowired
    private MinioClient minioClient;

@Autowired
    private MinioConfiguration configuration;

/**
     * @description: 获取上传临时签名,公众 号Java精选
     * @dateTime: 2021/5/13 14:12
     */
    public Map getPolicy(String fileName, ZonedDateTime time) {
        PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);
        postPolicy.addEqualsCondition(“key”, fileName);
        try {
            Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
            HashMap<String, String> map1 = new HashMap<>();
            map.forEach((k,v)->{
               map1.put(k.replaceAll(“-”,“”),v);
           });
            map1.put(“host”,configuration.getUrl()+“/”+configuration.getBucketName());
            return map1;
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }
        return null;
    }

/**
     * @description: 获取上传文件的url,公众 号Java精选,有惊喜!
     * @dateTime: 2021/5/13 14:15
     */
    public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(method)
                    .bucket(configuration.getBucketName())
                    .object(objectName)
                    .expiry(time, timeUnit).build());
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        }
        return null;
    }

/**
     * @description: 上传文件
     * @dateTime: 2021/5/13 14:17
     /
    public void upload(MultipartFile file, String fileName) {
        // 使用putObject上传一个文件到存储桶中。
        try {
            InputStream inputStream = file.getInputStream();
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(configuration.getBucketName())
                    .object(fileName)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }
    }
  /
*
     * @description: 根据filename获取文件访问地址
     * @dateTime: 2021/5/17 11:28
     */
    public String getUrl(String objectName, int time, TimeUnit timeUnit) {
        String url = null;
        try {
            url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(configuration.getBucketName())
                    .object(objectName)
                    .expiry(time, timeUnit).build());
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        }
        return url;
    }
}
`

简单说明:

  • 使用MultipartFile接收前端文件流,再上传到minio。

  • 构建一个formData的签名数据,给前端,让前端之前上传到minio。

  • 构建一个可以上传的临时URL给前端,前端通过携带文件请求该URL进行上传。

  • 使用filename请求服务端获取临时访问文件的URL。(最长时间为7 天,想要永久性访问,需要其他设置,这里不做说明。)

  • 推荐,公众 号Java精选,回复java面试,获取面试资料,支持在线刷题。

下面展示页面html,使用的是VUE+element-ui进行渲染。

`

          上传图片


        
            


                

                    

传统上传


                    
                        
                        
将文件拖到此处,或 点击上传

                        
只能上传jpg/png文件,且不超过500kb

                    
                    

                        
                    

                

            

        
        
            

                

                    

前端formData直传


                    
                        
                        
将文件拖到此处,或 点击上传

                        
只能上传jpg/png文件,且不超过500kb

                    
                    

                        
                    

                

            

        
        
            

                

                    

前端Url直传


                    
                        
                        
将文件拖到此处,或 点击上传

                        
只能上传jpg/png文件,且不超过500kb

                    
                    

                        
                    

                

            

        
    

uploadHandle(options) {
                let {file} = options;
                this.traditionPost(file);
            },
            traditionPost(file) {
                _that = this
                const form = new FormData();
                form.append(“fileName”, file.name);
                form.append(“file”, file);
                this.axiosPost(“post”, “/upload”, form).then(function (res) {
                    if (res.status === 200) {
                        _that.imgUrl = res.data.data
                    } else {
                        alert(“上传失败!”)
                    }
                })
            },
            getpolicy(file) {
                _that = this
                axios.get(‘policy?fileName=’ + file.name)
                    .then(function (response) {
                        let {xamzalgorithm, xamzcredential, policy, xamzsignature, xamzdate, host} = response.data.data;
                        let formData = new FormData();
                        formData.append(“key”, file.name);
                        formData.append(“x-amz-algorithm”, xamzalgorithm);  // 让服务端返回200,不设置则默认返回204。
                        formData.append(“x-amz-credential”, xamzcredential);
                        formData.append(“policy”, policy);
                        formData.append(“x-amz-signature”, xamzsignature);
                        formData.append(“x-amz-date”, xamzdate);
                        formData.append(“file”, file);
                        // 发送 POST 请求
                        _that.axiosPost(“post”, host, formData).then(function (res) {
                            if (res.status === 204) {
                                axios.get(‘url?fileName=’ + file.name).then(function (res) {
                                    _that.directUrl = res.data.data;
                                })
                            } else {
                                alert(“上传失败!”)
                            }
                        })
                    })
            },
            httpRequestHandle(options) {
                let {file} = options;
                this.getpolicy(file);
            },

UrlUploadHandle(options) {
                let {file} = options;
                this.getUploadUrl(file);
            },
            getUploadUrl(file) {
                _that = this
                console.log(file)
                axios.get(‘uploadUrl?fileName=’ + file.name)
                    .then(function (response) {
                        let url = response.data.data;
                        // 发送 put 请求
                        let config = {‘Content-Type’: file.type}
                        _that.axiosPost(“put”, url, file, config).then(function (res) {
                            if (res.status === 200) {
                                axios.get(‘url?fileName=’ + file.name).then(function (res) {
                                    _that.uploadUrl = res.data.data;
                                })
                            } else {
                                alert(“上传失败!”)
                            }
                        })
                    })
            },
            //封装
            //axios封装post请求
            axiosPost(method, url, data, config) {
                let result = axios({
                    method: method,
                    url: url,
                    data: data,
                    headers: config
                }).then(resp => {
                    return resp
                }).catch(error => {
                    return “exception=” + error;
                });
                return result;
            }

}
    })

`

图片

页面的效果就如上图所示。

可以分别体验不同的实现效果。

以上就是使用springboot搭建基于minio的高性能存储服务的全部步骤了。

本项目地址:

https://gitee.com/jack_whh/minio-upload

作者:HUWD

https://blog.csdn.net/weixin_45089791/article/details/116921075/

相关文章:

SpringBoot + minio实现分片上传、秒传、续传

什么是minio MinIO是一个基于Go实现的高性能、兼容S3协议的对象存储。它采用GNU AGPL v3开源协议&#xff0c;项目地址是https://github.com/minio/minio。 引用官网&#xff1a; MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储。它与Amazon S3云存储服务兼容…...

logback 里面设置 自动删除3天之前的日志

目录 1 实现 1 实现 要实现达到一定大小后将日志文件压缩&#xff0c;并删除三天前的日志数据&#xff0c;可以结合使用 SizeAndTimeBasedRollingPolicy 滚动策略和 DeleteOlderThan 选项来配置。下面是一个示例配置&#xff0c;实现日志文件达到一定大小后进行滚动和压缩&…...

对于数据库查询索引和查字典索引的理解

之前面试问过我对于数据库索引的理解&#xff0c;这个问题不是具体的问题太宽泛&#xff0c;面试官也没进行引导&#xff0c;我不知道怎么回答&#xff0c;下面是结合查字典进行理解。 查字典 拿查字典举例&#xff0c;知道一个字怎么写但是不知道具体的意思以及发音&#xff…...

git删除已经提交的大文件

当你不小心把一个巨大的二进制文件提交到git仓库的时候&#xff0c;此时删除再提交也没有用了&#xff0c;大文件已经在仓库中留底了。另外比如需要删除某个需要保密的文件&#xff0c;都是相同的解决办法。 我本来想着把dll放在三方库里面提交到仓库里&#xff0c;省得在不同…...

【数据分析】pandas 一

目录 一&#xff0c;pandas简介&#xff1a; 二&#xff0c;pandas数据结构Series简介&#xff1a; 2.1 data为ndarray 2.2 data为字典 三&#xff0c;Serise切片操作&#xff1a; 四&#xff0c;Series性质&#xff1a; 4.1 Series类似于numpy,字典 4.2 矢量化操作和标…...

题解 | #G.Gcd# 2023牛客暑期多校6

G.Gcd 数论 题目大意 给定一个包含两个非负数的初始集合 S { x , y } S\{x,y\} S{x,y} 每次操作可以选定其中不相等的两个数 a , b a,b a,b &#xff0c;并将 a − b a-b a−b 或 g c d ( a , b ) gcd(a,b) gcd(a,b) 置入集合 S S S &#xff0c;其中 g c d ( 0 , a …...

苍穹外卖day10——订单状态定时处理(Spring Task)、来单提醒和客户催单(WebSocket)

预期效果 对于超时没处理的需要定时程序处理。基于SpringTask实现。 来单提醒和客户催单。基于WebSocket实现。 Spring Task 介绍 Cron表达式 周几通常不能和日一起指定。 cron表达式在线生成器 在线Cron表达式生成器 入门案例 创建定时任务类 /*** 定义定时任务类*/ Slf4j…...

【多线程初阶】多线程案例之单例模式

文章目录 前言1. 什么是单例模式2. 饿汉模式3. 懒汉模式 --- 单线程版4. 懒汉模式 --- 多线程版5. 懒汉模式 --- 多线程改进版总结 前言 本文主要给大家讲解多线程的一个重要案例 — 单例模式. 关注收藏, 开始学习吧&#x1f9d0; 1. 什么是单例模式 单例模式是一种很经典的…...

跨境选品怎么选?建议独立站卖家收下这份利基产品查找攻略!

跨境电商平台现在可谓是火热发展中&#xff0c;独立站出海风口&#xff0c;其实选择的机会还真不少&#xff0c;相比国内电商的发展势头&#xff0c;看得出来&#xff0c;未来跨境电商的大门&#xff0c;对你而言&#xff0c;敞开着。选品这事儿&#xff0c;就像你上战场前挑选…...

[C++项目] Boost文档 站内搜索引擎(1): 项目背景介绍、相关技术栈、相关概念介绍...

项目背景 Boost库是C中一个非常重要的开源库. 它实现了许多C标准库中没有涉及的特性和功能, 一度成为了C标准库的拓展库. C新标准的内容, 很大一部分脱胎于Boost库中. Boost库的高质量代码 以及 提供了更多实用方便的C组件, 使得Boost库在C开发中会被高频使用 为方便开发者学…...

opencv-32 图像平滑处理-高斯滤波cv2.GaussianBlur()

在进行均值滤波和方框滤波时&#xff0c;其邻域内每个像素的权重是相等的。在高斯滤波中&#xff0c;会将中心点的权重值加大&#xff0c;远离中心点的权重值减小&#xff0c;在此基础上计算邻域内各个像素值不同权重 的和。 基本原理 在高斯滤波中&#xff0c;卷积核中的值不…...

Windows 环境Kubernetes安装

目录 前言 安装 Docker 安装 Kubernetes Windows 安装 kubectl 介绍 安装 开启 Kubernetes 前言 Docker作为当前最流行的容器化平台&#xff0c;为Kubernetes提供了强大的容器化技术基础。Kubernetes与Docker的结合&#xff0c;使得容器化应用程序在大规模集群中得以简…...

自建类ChatGPT服务:本地化部署与远程访问教程

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

常用SQL语句总结

SQL语句 文章目录 SQL语句1 SQL语句简介2 DQL&#xff08;数据查询语句&#xff09;3 DML&#xff08;数据操纵语句&#xff09;4 DDL&#xff08;数据定义语句&#xff09;5 DCL&#xff08;数据控制语句&#xff09;6 TCL&#xff08;事务控制语句&#xff09; 1 SQL语句简介…...

arm交叉编译lmbench

一、下载lmbench www.bitmover.com/lmbench 官网下载&#xff0c;http://www.bitmover.com/lmbench/lmbench3.tar.gz 我没有下载下来&#xff0c;找的别人的百度云下载 链接: https://pan.baidu.com/s/1tGo1clCqY-jQPN8G1eWSsg 提取码: f6jd 二、修改makefile 修改三个文件…...

ExtJs 7.7.0 下载方法与去除trial水印

背景 最近发现Sencha ExtJs发布了ExtJs7.7.0版本&#xff0c;立刻下载了SDK包&#xff0c;许多朋友不知如何下载&#xff0c;如何去除右上角的trial水印。本文讲下相关下载技巧与方法。 下载SDK 首先需要申请试用&#xff0c;申请地址如下&#xff0c;需要注意可能需要梯子&…...

Android11开发规划

文章目录 规划总结规划 提示:这里可以添加本文要记录的大概内容: 从本文开始,会介绍如何移植瑞芯微提供的Android11源码到自己的RK3568的板子上 下面是整个Android开发的规划: 包括以下部分: … 一、移植部分 下载编译瑞芯微提供的源码 瑞芯微原厂源码目录介绍...

活动隔断在现在酒店运用的方式

活动隔断是一种在酒店内部划分空间的方式&#xff0c;用于实现不同活动的隔离和隐私。现代酒店常用的活动隔断方式有以下几种&#xff1a; 1. 固定隔断&#xff1a;使用墙体、固定屏风或者板材等材料&#xff0c;将空间划分为不同的房间或区域。这种方式常用于划分客房、会议室…...

Jenkins工具系列 —— 插件 钉钉发送消息

文章目录 安装插件 Ding TalkJenkins 配置钉钉机器人钉钉APP配置项目中启动钉钉通知功能 安装插件 Ding Talk 点击 左侧的 Manage Jenkins —> Plugins ——> 左侧的 Available plugins Jenkins 配置钉钉机器人 点击 左侧的 Manage Jenkins &#xff0c;拉到最后 钉…...

LeetCode 26 题:删除有序数组的重复项

思路 在写这一个题时&#xff0c;我突然想到了Python中的 set&#xff08;&#xff09;函数可能会有大用处&#xff0c;便选择了用Python写。 set&#xff08;&#xff09;函数可以将列表转化为集合&#xff0c;集合会保证元素的单一性&#xff0c;所以会自动删去相同字符。 …...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...