经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
SpringBoot使用Minio进行文件存储的实现
来源:jb51  时间:2022/7/25 17:15:53  对本文有异议

一、minio

MinIO 是一个高性能的对象存储原生支持 Kubernetes 部署的解决方案。 MinIO 提供了一个 Amazon Web Services S3 兼容 API 并支持所有核心 S3 功能。

MinIO 对象存储使用 buckets 来组织对象。 存储桶类似于文件系统中的文件夹或目录,其中每个 桶可以容纳任意数量的对象。 MinIO 存储桶提供 与 AWS S3 存储桶相同的功能。

其中 MinIO 的优势有:

高性能:

MinIO是全球领先的对象存储先锋,在标准硬件上,读/写速度上高达183 GB / 秒171 GB / 秒

可扩展性:

MinIO利用了web缩放器的来之不易的知识,为对象存储带来了简单的存储缩放模型, 在 MinIO, 扩展从单个群集开始,该群集可以与其他MinIO群集联合以创建全局名称空间, 并在需要时可以跨越多个不同的数据中心。 通过添加更多集群可以扩展名称空间, 更多机架,直到实现目标。

云原生支持:

MinIO 是在过去4年的时间内从0开始打造的一款软件 ,符合一切原生云计算的架构和构建过程,并且包含最新的云计算的全新的技术和概念。 其中包括支持Kubernetes 、微服和多租户的的容器技术。使对象存储对于 Kubernetes更加友好。

源码开放与企业级支持:

MinIO 基于Apache V2 license 100% 开放源代码 。 这就意味着 MinIO的客户能够自动的、无限制、自由免费使用和集成MinIO、自由的创新和创造、 自由的去修改、自由的再次发行新的版本和软件. 确实, MinIO 强有力的支持和驱动了很多世界500强的企业。 此外,其部署的多样性和专业性提供了其他软件无法比拟的优势。

官方文档地址:http://docs.minio.org.cn/minio/baremetal/

在实验开始前请确保安装完成了 minio

二、SpringBoot 使用 Minio 进行文件存储

首先新建一个 SpringBoot 项目,在 pom 中引入 minio 依赖:

  1. <dependency>
  2. <groupId>io.minio</groupId>
  3. <artifactId>minio</artifactId>
  4. <version>8.2.1</version>
  5. </dependency>

在配置文件中,声明出 minio 的信息:

  1. minio:
  2. url: http://192.168.40.169:9000 # minio配置的地址,端口9000,注意不是控制台的端口
  3. accessKey: minioadmin # 账号
  4. secretKey: minioadmin # 密码
  5. bucketName: test-bucket # MinIO桶名字

下面创建一个配置类,对 MinioClient 进行创建:

  1. @Data
  2. @Configuration
  3. @ConfigurationProperties(prefix = "minio")
  4. public class MinioConfig {
  5. /**
  6. * 服务地址
  7. */
  8. private String url;
  9. /**
  10. * 用户名
  11. */
  12. private String accessKey;
  13. /**
  14. * 密码
  15. */
  16. private String secretKey;
  17. /**
  18. * 存储桶名称
  19. */
  20. private String bucketName;
  21.  
  22. @Bean
  23. public MinioClient getMinioClient() throws Exception {
  24. MinioClient minioClient = MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
  25. //判断桶是否存在,不存在则新建
  26. if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())){
  27. minioClient.makeBucket(MakeBucketArgs.builder()
  28. .bucket(bucketName)
  29. .build());
  30. }
  31. return minioClient;
  32. }
  33. }

下面创建一个工具类 MinioTool 将常用的操作封装在工具类中:

  1. @Component
  2. public class MinioTool {
  3. @Autowired
  4. private MinioClient minioClient;
  5.  
  6. @Autowired
  7. private MinioConfig minioConfig;
  8. /**
  9. * 查看存储bucket是否存在
  10. *
  11. * @param bucketName 存储bucket
  12. * @return boolean
  13. */
  14. public Boolean bucketExists(String bucketName) {
  15. Boolean found;
  16. try {
  17. found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. return false;
  21. }
  22. return found;
  23. }
  24. /**
  25. * 创建存储bucket
  26. *
  27. * @param bucketName 存储bucket名称
  28. * @return Boolean
  29. */
  30. public Boolean makeBucket(String bucketName) {
  31. try {
  32. minioClient.makeBucket(MakeBucketArgs.builder()
  33. .bucket(bucketName)
  34. .build());
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. return false;
  38. }
  39. return true;
  40. }
  41. /**
  42. * 删除存储bucket
  43. *
  44. * @param bucketName 存储bucket名称
  45. * @return Boolean
  46. */
  47. public Boolean removeBucket(String bucketName) {
  48. try {
  49. minioClient.removeBucket(RemoveBucketArgs.builder()
  50. .bucket(bucketName)
  51. .build());
  52. } catch (Exception e) {
  53. e.printStackTrace();
  54. return false;
  55. }
  56. return true;
  57. }
  58.  
  59. /**
  60. * 查看文件对象
  61. *
  62. * @param bucketName 存储bucket名称
  63. * @return 存储bucket内文件对象信息
  64. */
  65. public Iterable<Result<Item>> listObjects(String bucketName) {
  66. Iterable<Result<Item>> results = minioClient.listObjects(
  67. ListObjectsArgs.builder().bucket(bucketName).build());
  68. return results;
  69. }
  70.  
  71. /**
  72. * 批量删除文件对象
  73. *
  74. * @param bucketName 存储bucket名称
  75. * @param objects 对象名称集合
  76. */
  77. public Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> objects) {
  78. List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
  79. Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
  80. return results;
  81. }
  82.  
  83.  
  84. /**
  85. * 文件上传
  86. * 文件名称相同会覆盖
  87. * @param file 文件
  88. * @return Boolean
  89. */
  90. public Boolean upload(MultipartFile file, String fileName) {
  91. try {
  92. if (!bucketExists(minioConfig.getBucketName())) {
  93. makeBucket(minioConfig.getBucketName());
  94. }
  95. PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName)
  96. .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
  97. minioClient.putObject(objectArgs);
  98. } catch (Exception e) {
  99. e.printStackTrace();
  100. return false;
  101. }
  102. return true;
  103. }
  104. /**
  105. * 文件下载
  106. *
  107. * @param fileName 文件名称
  108. * @param res response
  109. * @return Boolean
  110. */
  111. public void download(String fileName, HttpServletResponse res) {
  112. GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(minioConfig.getBucketName())
  113. .object(fileName).build();
  114. try (GetObjectResponse response = minioClient.getObject(objectArgs)) {
  115. byte[] buf = new byte[1024];
  116. int len;
  117. try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
  118. while ((len = response.read(buf)) != -1) {
  119. os.write(buf, 0, len);
  120. }
  121. os.flush();
  122. byte[] bytes = os.toByteArray();
  123. res.setCharacterEncoding("utf-8");
  124. //设置强制下载不打开
  125. res.setContentType("application/force-download");
  126. res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
  127. try (ServletOutputStream stream = res.getOutputStream()) {
  128. stream.write(bytes);
  129. stream.flush();
  130. }
  131. }
  132. } catch (Exception e) {
  133. e.printStackTrace();
  134. }
  135. }
  136.  
  137. public String getFileUrl(String fileName){
  138. return StringFormatter.concat(minioConfig.getUrl(), "/", minioConfig.getBucketName(), "/", fileName).getValue();
  139. }
  140.  
  141. }

编写测试接口,进行测试:

  1. @Component
  2. public class MinioTool {
  3. @Autowired
  4. private MinioClient minioClient;
  5.  
  6. @Autowired
  7. private MinioConfig minioConfig;
  8. /**
  9. * 查看存储bucket是否存在
  10. *
  11. * @param bucketName 存储bucket
  12. * @return boolean
  13. */
  14. public Boolean bucketExists(String bucketName) {
  15. Boolean found;
  16. try {
  17. found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. return false;
  21. }
  22. return found;
  23. }
  24. /**
  25. * 创建存储bucket
  26. *
  27. * @param bucketName 存储bucket名称
  28. * @return Boolean
  29. */
  30. public Boolean makeBucket(String bucketName) {
  31. try {
  32. minioClient.makeBucket(MakeBucketArgs.builder()
  33. .bucket(bucketName)
  34. .build());
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. return false;
  38. }
  39. return true;
  40. }
  41. /**
  42. * 删除存储bucket
  43. *
  44. * @param bucketName 存储bucket名称
  45. * @return Boolean
  46. */
  47. public Boolean removeBucket(String bucketName) {
  48. try {
  49. minioClient.removeBucket(RemoveBucketArgs.builder()
  50. .bucket(bucketName)
  51. .build());
  52. } catch (Exception e) {
  53. e.printStackTrace();
  54. return false;
  55. }
  56. return true;
  57. }
  58.  
  59. /**
  60. * 查看文件对象
  61. *
  62. * @param bucketName 存储bucket名称
  63. * @return 存储bucket内文件对象信息
  64. */
  65. public Iterable<Result<Item>> listObjects(String bucketName) {
  66. Iterable<Result<Item>> results = minioClient.listObjects(
  67. ListObjectsArgs.builder().bucket(bucketName).build());
  68. return results;
  69. }
  70.  
  71. /**
  72. * 批量删除文件对象
  73. *
  74. * @param bucketName 存储bucket名称
  75. * @param objects 对象名称集合
  76. */
  77. public Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> objects) {
  78. List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
  79. Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
  80. return results;
  81. }
  82.  
  83.  
  84. /**
  85. * 文件上传
  86. * 文件名称相同会覆盖
  87. * @param file 文件
  88. * @return Boolean
  89. */
  90. public Boolean upload(MultipartFile file, String fileName) {
  91. try {
  92. if (!bucketExists(minioConfig.getBucketName())) {
  93. makeBucket(minioConfig.getBucketName());
  94. }
  95. PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName)
  96. .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
  97. minioClient.putObject(objectArgs);
  98. } catch (Exception e) {
  99. e.printStackTrace();
  100. return false;
  101. }
  102. return true;
  103. }
  104. /**
  105. * 文件下载
  106. *
  107. * @param fileName 文件名称
  108. * @param res response
  109. * @return Boolean
  110. */
  111. public void download(String fileName, HttpServletResponse res) {
  112. GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(minioConfig.getBucketName())
  113. .object(fileName).build();
  114. try (GetObjectResponse response = minioClient.getObject(objectArgs)) {
  115. byte[] buf = new byte[1024];
  116. int len;
  117. try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
  118. while ((len = response.read(buf)) != -1) {
  119. os.write(buf, 0, len);
  120. }
  121. os.flush();
  122. byte[] bytes = os.toByteArray();
  123. res.setCharacterEncoding("utf-8");
  124. //设置强制下载不打开
  125. res.setContentType("application/force-download");
  126. res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
  127. try (ServletOutputStream stream = res.getOutputStream()) {
  128. stream.write(bytes);
  129. stream.flush();
  130. }
  131. }
  132. } catch (Exception e) {
  133. e.printStackTrace();
  134. }
  135. }
  136.  
  137. public String getFileUrl(String fileName){
  138. return StringFormatter.concat(minioConfig.getUrl(), "/", minioConfig.getBucketName(), "/", fileName).getValue();
  139. }
  140.  
  141. }

三、测试

测试上传文件:

如果使用 返回的 url 直接访问文件,可以发现返回权限不足:

这里需要改一下 BucketAccess Policy ,默认为 private,可以修改为 public 便无需认证,但安全性无法保证:

再次进行访问,文件就可以打开了:

如果需要保持 private ,可以通过 MinioClient 进行下载,使用 download 测试接口下载文件:http://localhost:8080/file/download/20cab4e3979eba6003f95aca0dc75c63.jpg

 到此这篇关于SpringBoot使用Minio进行文件存储的实现的文章就介绍到这了,更多相关SpringBoot Minio文件存储内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号