如何使用docker创建minio镜像并上传文件并提供demo
作者:天河归来
使用docker创建minio镜像并上传文件,提供demo
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"
看到如下就说明启动成功了:
然后通过浏览器访问:http://localhost:9001/进入如下登录页面:默认用户名和密码都是minioadmin
2.2 docker部署
使用docker部署就更简单了,首先拉取官方镜像:
docker pull minio/minio
拉取成功之后,执行创建和启动容器:
docker run -p 9000:9000 -p 9001:9001 minio/minio server /data --console-address ":9001"
看到如下就说明启动成功:
同样通过浏览器访问: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:9000 accessKey: minioadmin secretKey: 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 */ @Bean public 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); @Autowired private MinioUtil minioUtil; @Override public 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); @Autowired private MinioUtil minioUtil; @RequestMapping("/test") @ResponseBody public 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说明连接成功:
4.2 页面查看
运行完成,在页面应该能看到我们创建的桶:
4.3 上传文件
使用postman调用我们写的测试接口,上传一个文件到minio
上传成功,在页面上也可以看到这个文件:
4.4 预览/下载文件
如果上传的是图片,通过返回的url,浏览器可以直接访问预览,如果是其他类型的文件,是可以通过这个返回的url进行下载的:http://localhost:9000/test/20230908/2b31664c4a004a5cb4b2934ebf5300cd.jpg
5. demo下载
minio的demo已经上传到csdn,需要的可以自行下载,在本文基本也把主要的核心代码都贴出来了,这个demo使用的是springboot框架,加了一些工具类,可以直接拿来用,或者新工程改个名字就能用了。demo结构截图:
demo工程地址:demo下载地址,传到了gitcode上,应该是csdn弄的一个代码仓库,和git差不多。
6. 总结
minio还是很方便的,从部署到使用,都可以非常快速的搭建,而且比较稳定。
到此这篇关于使用docker创建minio镜像并上传文件,提供demo的文章就介绍到这了,更多相关docker创建minio镜像内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!