MinIO是一个基于Go实现的高性能、兼容S3协议的对象存储。它采用GNU AGPL v3开源协议,项目地址是https://github.com/minio/minio。
引用官网:
MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储。它与Amazon S3云存储服务兼容。使用MinIO构建用于机器学习,分析和应用程序数据工作负载的高性能基础架构。
官网地址:
文档地址:
MinIO Object Storage for Kubernetes — MinIO Object Storage for Kubernetes
- 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上运行的。
当启动后在浏览器访问http://localhost:9000
就可以访问minio的图形化界面了,如图所示:
初始化一个springboot项目大家都会,这里不多做介绍。
主要是介绍需要引入的依赖:
-
org.springframework.boot -
spring-boot-starter-thymeleaf -
io.minio -
minio -
8.2.1 -
org.projectlombok -
lombok -
true
依赖可以官方文档里找: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: 获取上传临时签名
- */
- public Map getPolicy(String fileName, ZonedDateTime time) {
- PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);
- postPolicy.addEqualsCondition("key", fileName);
- try {
- Map
map = minioClient.getPresignedPostFormData(postPolicy); - HashMap
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
- */
- 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: 上传文件
- */
- 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获取文件访问地址
- */
- 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 天,想要永久性访问,需要其他设置,这里不做说明。)
下面展示页面html,使用的是VUE+element-ui进行渲染。
- "UTF-8">
-
- "stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
-
上传图片 - "app">
-
-
"2"> -
"8"> - "div-center-class">
- "">
-
传统上传
-
- class="upload-demo"
- action="#"
- drag
- :http-request="uploadHandle">
- "el-icon-upload">
- "el-upload__text">将文件拖到此处,或点击上传
- "el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb
-
- if="imgUrl">
- "imgUrl" style="width: 40px;height: 40px">
-
-
-
-
-
"8"> - "div-center-class">
- "">
-
前端formData直传
-
- class="upload-demo"
- action="#"
- drag
- :http-request="httpRequestHandle">
- "el-icon-upload">
- "el-upload__text">将文件拖到此处,或点击上传
- "el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb
-
- if="directUrl">
- "directUrl" style="width: 40px;height: 40px">
-
-
-
-
-
"8"> - "div-center-class">
- "">
-
前端Url直传
-
- class="upload-demo"
- action="#"
- drag
- :http-request="UrlUploadHandle">
- "el-icon-upload">
- "el-upload__text">将文件拖到此处,或点击上传
- "el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb
-
- if="uploadUrl">
- "uploadUrl" style="width: 40px;height: 40px">
-
-
-
-
-
- new Vue({
- el: '#app',
- data: function () {
- return {
- imgUrl: '',
- directUrl: '',
- uploadUrl: ''
- }
- },
- methods: {
-
- 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;
- }
-
- }
- })
- .div-center-class {
- padding: 28% 0%;
- text-align: center;
- background: beige;
- }
页面的效果就如上图所示。
可以分别体验不同的实现效果。
以上就是使用springboot搭建基于minio的高性能存储服务的全部步骤了。
本项目地址:
https://gitee.com/jack_whh/minio-upload
-
相关阅读:
Springboot 引入第三方jar包,并打包运行
C++学习资源
Linux内核设计与实现 第六章 内核数据结构
Leetcode739. 每日温度
低代码掀起“数字革命”,引领制造业数字化转型
Jmeter基础入门教程【12】--常用功能详解:JDBC
基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持自定义业务表单流程(一)
网络流问题
Spring MVC基于注解的使用:JSON数据处理
【云原生】k8s中volumeMounts.subPath的巧妙用法
-
原文地址:https://blog.csdn.net/LU58542226/article/details/133104926