使用docker创建minio镜像并上传文件,提供demo

使用docker创建minio镜像并上传文件,提供demo

  • 1. 整体描述
  • 2. 环境搭建
    • 2.1 windows环境搭建
    • 2.2 docker部署
  • 3. spring集成
    • 3.1 添加依赖
    • 3.2 配置文件
    • 3.3 创建config类
    • 3.4 创建minio操作类
    • 3.5 创建启动类
    • 3.6 测试controller
  • 4. 测试操作
    • 4.1 demo运行
    • 4.2 页面查看
    • 4.3 上传文件
    • 4.4 预览/下载文件
  • 5. demo下载
  • 6. 总结

1. 整体描述

MinIO是一个对象存储解决方案,它提供了一个Amazon Web Services S3兼容的API,并支持所有S3的核心特性。MinIO可以部署在任何地方——公共云或私有云、裸机基础设施、编排环境和边缘基础设施。

本文档介绍MinIO最新稳定版本RELEASE.2023-09-04T19-57-37Z在Windows平台上部署MinIO的操作、管理和开发。

上面是官网介绍,用有道翻译的,官网地址: 链接。

2. 环境搭建

使用docker搭建minio环境,可以直接用官网下载minio镜像,我们先用windows环境搭建一下。

2.1 windows环境搭建

在官网下载页面,选择windows,下载的是一个minion.exe文件。我放在了d:/minio目录下,在此再创建一个data文件夹,用来储存minio上传的文件。
然后在命令行执行如下指令启动minio:

setx MINIO_ROOT_USER minioadmin
setx MINIO_ROOT_PASSWORD minioadmin
D:\minio\minio.exe server D:\minio\data\ --console-address ":9001"

看到如下就说明启动成功了:
windowsminio启动
然后通过浏览器访问:
http://localhost:9001/
进入如下登录页面:
默认用户名和密码都是minioadmin
minio登录页面

2.2 docker部署

使用docker部署就更简单了,首先拉取官方镜像:

docker pull minio/minio

拉取成功之后,执行创建和启动容器:

docker run -p 9000:9000 -p 9001:9001 minio/minio server /data --console-address ":9001"

看到如下就说明启动成功:
docker启动minio
同样通过浏览器访问:
http://localhost:9001/
进入如下登录页面:
默认用户名和密码都是minioadmin

3. spring集成

通过springboot框架集成minio,实现上传文件的目的。

3.1 添加依赖

首先创建一个springboot工程,添加如下依赖:

<!-- lombok 自动生成方法--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><!--io常用工具类 --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.5</version></dependency><!--常用工具类 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><!-- minio--><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.4.6</version></dependency>

3.2 配置文件

在springboot的yml配置文件中添加minio环境的配置:

#minio相关配置
minio:endpoint: http://127.0.0.1:9000accessKey: minioadminsecretKey: minioadmin

3.3 创建config类

package com.thcb.miniodemo.config;import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;/*** MinioUtil** @author thcb* @date 2023-09-05*/
@Component
public class MinioClientConfig {@Value("${minio.endpoint}")private String endpoint;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;/*** 注入minio 客户端** @return*/@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();}}

3.4 创建minio操作类

minio操作类,用来写minio基础方法

package com.thcb.miniodemo.minio;import com.thcb.miniodemo.utils.*;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;/*** MinioUtil** @author thcb* @date 2023-09-05*/
@Component
@Slf4j
@RequiredArgsConstructor
public class MinioUtil {private final MinioClient minioClient;/*** 两票数据桶*/public static String TEST_BUCKET = "test";private static String POLICY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::%s\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::%s/*\"]}]}";public void initMinIo() {log.warn("start initMinIo.");if (!bucketExists(TEST_BUCKET)) {log.warn("start makeBucket {}.", TEST_BUCKET);makeBucket(TEST_BUCKET);log.warn("finish makeBucket {}.", TEST_BUCKET);}try {log.warn("start setBucketPolicy {}.", TEST_BUCKET);minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(TEST_BUCKET).config(String.format(POLICY, TEST_BUCKET, TEST_BUCKET)).build());log.warn("finish setBucketPolicy {}.", TEST_BUCKET);} catch (Exception e) {log.error("setBucketPolicy from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));}}/*** 查看存储bucket是否存在** @return boolean*/public Boolean bucketExists(String bucketName) {Boolean found;try {found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());} catch (Exception e) {log.error("bucketExists from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));return false;}return found;}/*** 创建存储bucket** @return Boolean*/public synchronized Boolean makeBucket(String bucketName) {try {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {log.error("makeBucket from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));return false;}return true;}/*** 删除存储bucket** @return Boolean*/public synchronized Boolean removeBucket(String bucketName) {try {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {log.error("removeBucket from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));return false;}return true;}/*** 获取全部bucket*/public List<Bucket> getAllBuckets() {try {List<Bucket> buckets = minioClient.listBuckets();return buckets;} catch (Exception e) {log.error("getAllBuckets from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));}return null;}/*** 文件上传** @param file       文件* @param bucketName 桶名称* @return Boolean*/public synchronized String upload2Bucket(MultipartFile file, String bucketName) {return String.format("/%s/%s", bucketName, upload(file, bucketName));}/*** 文件上传** @param file       文件* @param bucketName 桶名称* @return Boolean*/public synchronized String upload(MultipartFile file, String bucketName) {String originalFilename = file.getOriginalFilename();if (StringUtils.isBlank(originalFilename)) {throw new CustomException("文件格式错误");}String fileName = UUIDUtil.UUID() + originalFilename.substring(originalFilename.lastIndexOf("."));String objectName = DateUtils.dateTimeNow(DateUtils.YYYYMMDD) + "/" + fileName;try {PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();//文件名称相同会覆盖minioClient.putObject(objectArgs);} catch (Exception e) {log.error("upload file to minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));return null;}return objectName;}/*** 文件上传** @param file 文件* @return Boolean*/public synchronized String upload(MultipartFile file) {return upload(file, TEST_BUCKET);}/*** 预览** @param fileName* @return*/public String preview(String fileName) {return preview(fileName, TEST_BUCKET);}/*** 预览** @param fileName* @param bucketName 桶名称* @return*/public String preview(String fileName, String bucketName) {// 查看文件地址GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).method(Method.GET).build();try {String url = minioClient.getPresignedObjectUrl(build);return url;} catch (Exception e) {log.error("preview file to minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));}return null;}/*** 文件下载** @param fileName         文件名称* @param originalFileName 原文件名称* @param res              response* @return Boolean*/public void download(String fileName, String originalFileName, HttpServletRequest req, HttpServletResponse res) {download(fileName, TEST_BUCKET, req, res);}/*** 文件下载** @param fileName         文件名称* @param bucketName       桶名称* @param originalFileName 原文件名称* @param res              response* @return Boolean*/public void download(String fileName, String bucketName, String originalFileName, HttpServletRequest req, HttpServletResponse res) {GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(fileName).build();try (GetObjectResponse response = minioClient.getObject(objectArgs)) {byte[] buf = new byte[1024];int len;try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {while ((len = response.read(buf)) != -1) {os.write(buf, 0, len);}os.flush();byte[] bytes = os.toByteArray();res.setCharacterEncoding("utf-8");String type = req.getHeader("User-Agent").toLowerCase();String firefox = "firefox", chrome = "chrome";String encodedFileName;if (type.indexOf(firefox) > 0 || type.indexOf(chrome) > 0) {encodedFileName = new String(originalFileName.getBytes(StandardCharsets.UTF_8), "iso8859-1");} else {encodedFileName = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8.name());}// 设置强制下载不打开// res.setContentType("application/force-download");// res.setContentType("application/octet-stream");res.setContentType(FileDownloadUtils.getFileContentType(fileName));res.addHeader("Content-Disposition", "attachment;fileName=" + encodedFileName + ";filename*=utf-8''" + encodedFileName);res.addHeader("Content-Length", bytes.length + "");try (ServletOutputStream stream = res.getOutputStream()) {stream.write(bytes);stream.flush();}}res.flushBuffer();} catch (Exception e) {log.error("download file from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));}}/*** 删除** @param fileName* @return* @throws Exception*/public boolean remove(String fileName) {return remove(fileName, TEST_BUCKET);}/*** 删除** @param fileName* @return* @throws Exception*/public synchronized boolean remove(String fileName, String bucketName) {try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());} catch (Exception e) {log.error("remove file from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));return false;}return true;}}

3.5 创建启动类

在springboot启动成功后连接minio

package com.thcb.miniodemo.listener;import com.thcb.miniodemo.minio.MinioUtil;
import com.thcb.miniodemo.utils.ExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** ApplicationReadyListener** @author thcb* @date 2023-09-05*/
@Component
public class ApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {private static final Logger log = LoggerFactory.getLogger(ApplicationReadyListener.class);@Autowiredprivate MinioUtil minioUtil;@Overridepublic void onApplicationEvent(ApplicationReadyEvent event) {try {doPostConstruct();} catch (Exception e) {log.error("e={}", ExceptionUtil.getExceptionMessage(e));}}private void doPostConstruct() {log.info("initMinIo");initMinIo();}/*** 初始化minio桶文件*/private void initMinIo() {minioUtil.initMinIo();}
}

3.6 测试controller

写一个测试的controller,测试minio相关功能

package com.thcb.miniodemo.controller;import com.thcb.miniodemo.minio.MinioUtil;
import com.thcb.miniodemo.utils.AjaxResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;/*** TestController** @author thcb* @date 2023-09-05*/
@RestController
@RequestMapping("/TestController")
public class TestController {private static final Logger log = LoggerFactory.getLogger(TestController.class);@Autowiredprivate MinioUtil minioUtil;@RequestMapping("/test")@ResponseBodypublic String test() {return "test success";}@PostMapping("/uploadFile")public AjaxResult uploadFile(MultipartFile file) throws Exception {try {String pathUrl = minioUtil.upload2Bucket(file, MinioUtil.TEST_BUCKET);return AjaxResult.success(pathUrl);} catch (Exception e) {return AjaxResult.error(e.toString());}}
}

4. 测试操作

4.1 demo运行

运行工程,如下log说明连接成功:
miniodemo运行

4.2 页面查看

运行完成,在页面应该能看到我们创建的桶:
桶

4.3 上传文件

使用postman调用我们写的测试接口,上传一个文件到minio
postman调用
上传成功,在页面上也可以看到这个文件:
文件查看

4.4 预览/下载文件

如果上传的是图片,通过返回的url,浏览器可以直接访问预览,如果是其他类型的文件,是可以通过这个返回的url进行下载的:
http://localhost:9000/test/20230908/2b31664c4a004a5cb4b2934ebf5300cd.jpg

5. demo下载

minio的demo已经上传到csdn,需要的可以自行下载,在本文基本也把主要的核心代码都贴出来了,这个demo使用的是springboot框架,加了一些工具类,可以直接拿来用,或者新工程改个名字就能用了。demo结构截图:
demo结构
demo工程地址:demo下载地址,传到了gitcode上,应该是csdn弄的一个代码仓库,和git差不多。

6. 总结

minio还是很方便的,从部署到使用,都可以非常快速的搭建,而且比较稳定。

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

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

相关文章

普中51-数码管实验

文章目录 数码管实验**静态数码管实验**动态数码管实验多位数码管简介数码管动态显示原理74HC245 和74HC138芯片介绍74HC245 芯片简介74HC138 芯片简介 代码如下&#xff1a; 数码管实验 如图所示&#xff1a; 从上图可看出&#xff0c;一位数码管的引脚是 10 个&#xff0c;…

c++11的一些新特性

c11 1. {}初始化2. 范围for循环3. final与override4. 右值引用4.1 左值引用和右值引用4.2 左值引用与右值引用比较 5. lambda表达式6. 声明6.1 auto6.2 decltype6.3 nullptr 7. 可变参数模版 1. {}初始化 在C中&#xff0c;使用花括号初始化的方式被称为列表初始化。列表初始化…

C++:初始化列表,static成员,友元,内部类

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》 文章目录 前言一、初始化列表二、static成员三、友元四、内部类总结 前言 本篇博客作为C&#xff1a;初始化列表&#xff0c;static成员&#xff0c;友元&#xff0c;内部类的知识总结。 一…

java面向对象(二)

文章目录 一、方法1.例子2.例子3.例子 二、使用步骤1.举例说明类跟对象&#xff08;高大上&#xff09;2.理解“万事万物皆对象”3.变量在内存中的位置体现4.引用类型的变量5.匿名对象的使用 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、方法 描…

Mysql开启binlog

本案例基于mysql5.7.16实验 1、在linux中进入mysql查询binlog是否打开&#xff0c;执行命令如下&#xff1a; mysql -u root -p 2、查询binlog是否开启命令如下&#xff0c;如果log_bin为OFF则证明mysql的binlog没有打开 show variables like %log_bin%; 3、退出mysql终端&…

基于 Alpine 环境构建 aspnetcore6-runtime 的 Docker 镜像

关于 Alpine Linux 此处就不再过多讲述&#xff0c;请自行查看相关文档。 .NET 支持的体系结构 下表列出了当前支持的 .NET 体系结构以及支持它们的 Alpine 版本。 这些版本在 .NET 到达支持终止日期或 Alpine 的体系结构受支持之前仍受支持。请注意&#xff0c;Microsoft 仅正…

unity 使用声网(Agora)实现语音通话

第一步、先申请一个声网账号 [Agora官网链接]&#xff08;https://console.shengwang.cn/&#xff09; 第二步在官网创建项目 &#xff0c;选择无证书模式&#xff0c;证书模式需要tokenh和Appld才能通话 第三步 官网下载SDK 然后导入到unity&#xff0c;也可以直接在unity商店…

Spring-Cloud GateWay+Vue 跨域方案汇总

文章目录 一、简介背景和概述 二、前端跨域解决方案Axios跨域CORS跨域 三、后端跨域解决方案反向代理服务器 四、Spring Cloud中的跨域解决方案Gateway网关的跨域配置 五、基于Vue和Spring Cloud的跨域整合实践**这两种配置只需配置一种即可生效&#xff08;前端or后端&#xf…

Zookeeper 启动失败【Cannot open channel to 3 at election address...】

文章目录 完整报错信息解决方法1.检查文件夹权限2.未监听所有IP3.IP映射名称与 ID 不对应 完整报错信息 Cannot open channel to 3 at election address hadoop121/192.168.10.121:3888 java.net.ConnectException 解决方法 1.检查文件夹权限 检查当前用户是否拥有 Zookeep…

【SpringMVC】JSR 303与interceptor拦截器快速入门

目录 一、JSR303 1、什么是JSR 303&#xff1f; 2、为什么要使用JSR 303&#xff1f; 3、JSR 303常用注解 3.1、常用的JSR 303注解 3.2、Validated与Valid区别 3.2.1、Validated 3.2.2、Valid 3.2.3、区别 4、使用案例 4.1、导入依赖 4.2、配置校验规则 4.3、编写…

去耦电路设计应用指南(二)电容的噪声抑制

&#xff08;二&#xff09;电容的噪声抑制 1. 电容的频率特性1.1 MLCC1.2 LW逆转电容1.3 三端子电容 2. 电容layout3. 电容安装位置与干扰路径4. 多个电容并联及反谐振 由于电容自身的频率特性以及器件在 PCB 上面的 layout&#xff0c;在噪声抑制的效果也会受到影 响&#xf…

智慧公厕建设的好处

在现代社会的迅猛发展中&#xff0c;智慧公厕的建设越来越受到重视。通过智慧高效管理和保持公厕整洁&#xff0c;城市形象得以提升&#xff0c;为居民提供更加便捷舒适的生活服务。本文将以智慧公厕源头厂家广州中期科技有限公司&#xff0c;大量精品项目案例&#xff0c;实景…