• 你可需要的对象存储中间件《Minio使用》


    最近的项目中因为需要做一些上传和下载的工作,所以选择了minio。当然这也是公司的选择,废话不多说,今天主要是记录下经验。

    1、minio相关信息

    1.1 官方信息

    中文网站:MinIO | 高性能,对Kubernetes友好的对象存储

    你懂得,去掉cn 就是官方网站。在官方网站上有你要的信息。不打开看看吗?看起来了不起的样子

    MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。

    MinIO与传统的存储和其他的对象存储不同的是:它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。

    MinIO在传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。同时,它在机器学习、大数据、私有云、混合云等方面的存储技术上也独树一帜。当然,也不排除数据分析、高性能应用负载、原生云的支持。

    在中国:阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在使用MinIO产品

    1.2 MinIO优势

    1、数据安全

    分布式存储,保证数据安全

    2、高可用

    分布式多副本机制,可以保证服务的高可用,即使挂掉几个也能保证服务

    3、一致性

    1.3 应用场景

    互联网非结构化数据的存储需求

    • 电商网站:海量商品图片
    • 视频网站:海量视频文件
    • 网盘:海量文件

    2、部署

    懒省事,直接选择docker部署,看下脚本吧,没啥问题。

    1. docker run -p 9000:9000 --net=host \
    2. --name minio1 \
    3. -d \
    4. -e MINIO_ACCESS_KEY=minio \
    5. -e MINIO_SECRET_KEY=minio@123 \
    6. -v /home/docker/minio/data:/data \
    7. -v /home/docker/minio/config:/root/.minio \
    8. minio/minio server /data

    启动起来登录进控制台

    管理地址:http://172.26.1.152:9000/,用户名和地址在上面的脚本里

    3、Springboo继承Minio

    1、添加依赖

    这里在线上直接找了一个,你可以在repo里查找最新的 

    1. <dependency>
    2. <groupId>io.miniogroupId>
    3. <artifactId>minioartifactId>
    4. <version>8.0.0version>
    5. dependency>

    2、配置文件

    application.yml,这里直接创建了一个配置,你可以根据自己的需求定义格式

    1. minio:
    2. endpoint: http://172.26.1.152:9000 # endpoint
    3. accessKey: minio #用户名
    4. secretKey: minio@123 # 密码
    5. bucketName: apply # bucketName

    3、读取配置文件

    这里使用了lombok,如果你没使用的话,可以去除data注解,然后创建一些get/set方法。

    1. import io.minio.MinioClient;
    2. import lombok.Data;
    3. import org.springframework.boot.context.properties.ConfigurationProperties;
    4. import org.springframework.context.annotation.Bean;
    5. import org.springframework.context.annotation.Configuration;
    6. @Data
    7. @Configuration
    8. @ConfigurationProperties(prefix = "minio")
    9. public class MinioConfig {
    10. private String endpoint;
    11. private String accessKey;
    12. private String secretKey;
    13. @Bean
    14. public MinioClient minioClient() {
    15. MinioClient minioClient = MinioClient.builder()
    16. .endpoint(endpoint)
    17. .credentials(accessKey, secretKey)
    18. .build();
    19. return minioClient;
    20. }
    21. }

    4、创建一个工具类

    这里借鉴了一些线上的文档,然后加了一些修改,可以直接拷贝到项目中使用。

    1. package com.xin.miniodemo.config;
    2. import io.minio.*;
    3. import io.minio.messages.Bucket;
    4. import io.minio.messages.DeleteError;
    5. import io.minio.messages.DeleteObject;
    6. import io.minio.messages.Item;
    7. import lombok.extern.slf4j.Slf4j;
    8. import org.springframework.beans.factory.annotation.Autowired;
    9. import org.springframework.stereotype.Component;
    10. import org.springframework.util.FastByteArrayOutputStream;
    11. import org.springframework.web.multipart.MultipartFile;
    12. import javax.servlet.ServletOutputStream;
    13. import javax.servlet.http.HttpServletResponse;
    14. import java.util.ArrayList;
    15. import java.util.List;
    16. import java.util.stream.Collectors;
    17. /**
    18. * minio 工具类
    19. */
    20. @Component
    21. @Slf4j
    22. public class MinioUtil {
    23. @Autowired
    24. private MinioClient minioClient;
    25. /**
    26. * 查看存储bucket是否存在
    27. *
    28. * @return boolean
    29. */
    30. public boolean bucketExists(String bucketName) {
    31. boolean found = false;
    32. try {
    33. BucketExistsArgs args = BucketExistsArgs.builder().bucket(bucketName)
    34. .build();
    35. found = minioClient.bucketExists(args);
    36. } catch (Exception e) {
    37. log.error("bucketExists ", e);
    38. }
    39. return found;
    40. }
    41. /**
    42. * 创建存储bucket
    43. *
    44. * @return Boolean
    45. */
    46. public boolean makeBucket(String bucketName) {
    47. try {
    48. MakeBucketArgs makeArgs = MakeBucketArgs.builder()
    49. .bucket(bucketName)
    50. .build();
    51. minioClient.makeBucket(makeArgs);
    52. } catch (Exception e) {
    53. log.error("makeBucket ", e);
    54. return false;
    55. }
    56. return true;
    57. }
    58. /**
    59. * 删除存储bucket
    60. *
    61. * @return Boolean
    62. */
    63. public boolean removeBucket(String bucketName) {
    64. try {
    65. RemoveBucketArgs removeArgs = RemoveBucketArgs.builder()
    66. .bucket(bucketName)
    67. .build();
    68. minioClient.removeBucket(removeArgs);
    69. } catch (Exception e) {
    70. log.error("removeBucket ", e);
    71. return false;
    72. }
    73. return true;
    74. }
    75. /**
    76. * 获取全部bucket
    77. */
    78. public List getAllBuckets() {
    79. try {
    80. return minioClient.listBuckets();
    81. } catch (Exception e) {
    82. log.error("getAllBuckets ", e);
    83. }
    84. return null;
    85. }
    86. /**
    87. * 文件上传
    88. *
    89. * @param bucketName
    90. * @param fileName 上传文件的路径和名字
    91. * @param file
    92. * @return
    93. */
    94. public boolean upload(String bucketName, String fileName, MultipartFile file) {
    95. try {
    96. PutObjectArgs objectArgs = PutObjectArgs.builder()
    97. .bucket(bucketName)
    98. .object(fileName)
    99. .stream(file.getInputStream(), file.getSize(), -1)
    100. .contentType(file.getContentType())
    101. .build();
    102. //文件名称相同会覆盖
    103. minioClient.putObject(objectArgs);
    104. } catch (Exception e) {
    105. log.error("upload ", e);
    106. return false;
    107. }
    108. return true;
    109. }
    110. /**
    111. * 文件下载
    112. *
    113. * @param fileName 文件的路径和名字
    114. * @return Boolean
    115. */
    116. public void download(String fileName, String saveName, String bucketName) {
    117. DownloadObjectArgs build = DownloadObjectArgs.builder()
    118. .bucket(bucketName)
    119. .filename(saveName)
    120. .object(fileName)
    121. .build();
    122. try {
    123. minioClient.downloadObject(build);
    124. } catch (Exception e) {
    125. throw new RuntimeException(e);
    126. }
    127. }
    128. /**
    129. * web下载文件
    130. *
    131. * @param fileName 文件的路径和名字
    132. * @param bucketName
    133. * @param resp
    134. */
    135. public void webDownload(String fileName, String bucketName, HttpServletResponse resp) {
    136. GetObjectArgs objectArgs = GetObjectArgs.builder()
    137. .bucket(bucketName)
    138. .object(fileName)
    139. .build();
    140. try (GetObjectResponse response = minioClient.getObject(objectArgs)) {
    141. byte[] buf = new byte[1024];
    142. int len;
    143. try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
    144. while ((len = response.read(buf)) != -1) {
    145. os.write(buf, 0, len);
    146. }
    147. os.flush();
    148. byte[] bytes = os.toByteArray();
    149. resp.setCharacterEncoding("utf-8");
    150. //设置强制下载不打开
    151. //res.setContentType("application/force-download");
    152. resp.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
    153. try (ServletOutputStream stream = resp.getOutputStream()) {
    154. stream.write(bytes);
    155. stream.flush();
    156. }
    157. }
    158. } catch (Exception e) {
    159. log.error("webDownload ", e);
    160. }
    161. }
    162. /**
    163. * 查看文件对象
    164. *
    165. * @return 存储bucket内文件对象信息
    166. */
    167. public List listObjects(String bucketName) {
    168. ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
    169. .bucket(bucketName)
    170. .build();
    171. Iterable> results = minioClient.listObjects(listObjectsArgs);
    172. List itemList = new ArrayList<>();
    173. try {
    174. for (Result result : results) {
    175. itemList.add(result.get());
    176. }
    177. } catch (Exception e) {
    178. log.error("listObjects ", e);
    179. return null;
    180. }
    181. return itemList;
    182. }
    183. /**
    184. * 删除
    185. *
    186. * @param fileName
    187. * @return
    188. * @throws Exception
    189. */
    190. public boolean removeOne(String fileName, String bucketName) {
    191. try {
    192. RemoveObjectArgs removeArgs = RemoveObjectArgs.builder()
    193. .bucket(bucketName)
    194. .object(fileName)
    195. .build();
    196. minioClient.removeObject(removeArgs);
    197. } catch (Exception e) {
    198. log.error("remove ", e);
    199. return false;
    200. }
    201. return true;
    202. }
    203. /**
    204. * 批量删除文件对象
    205. *
    206. * @param objects 对象名称集合
    207. */
    208. public Iterable> removeObjects(List objects, String bucketName) {
    209. List dos = objects.stream().map(DeleteObject::new).collect(Collectors.toList());
    210. RemoveObjectsArgs build = RemoveObjectsArgs.builder()
    211. .bucket(bucketName)
    212. .objects(dos)
    213. .build();
    214. Iterable> results = minioClient.removeObjects(build);
    215. return results;
    216. }
    217. }

    5、测试代码,

    这里直接创建了一个controller测试

    1. import com.xin.miniodemo.config.MinioUtil;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.web.bind.annotation.PostMapping;
    4. import org.springframework.web.bind.annotation.RequestMapping;
    5. import org.springframework.web.bind.annotation.RestController;
    6. import org.springframework.web.multipart.MultipartFile;
    7. import javax.servlet.http.HttpServletResponse;
    8. import java.util.Arrays;
    9. import java.util.List;
    10. @RestController
    11. @RequestMapping
    12. public class TestController {
    13. @Autowired
    14. private MinioUtil minioUtil;
    15. @PostMapping("/upload")
    16. public String test(MultipartFile file) {
    17. minioUtil.upload("chongxin",file.getOriginalFilename(),file);
    18. return "Hello";
    19. }
    20. @PostMapping("/delete")
    21. public String delete(String fileName) {
    22. String[] fileArr = fileName.split(",");
    23. List fl = Arrays.asList(fileArr);
    24. minioUtil.removeObjects(fl,"chongxin");
    25. return "Hello";
    26. }
    27. @PostMapping("/download")
    28. public String download(String fileName) {
    29. minioUtil.download(fileName,"chongxin.jpg","chongxin.jpg");
    30. return "Hello";
    31. }
    32. @PostMapping("/webdownload")
    33. public String download(String fileName, HttpServletResponse response) {
    34. minioUtil.webDownload(fileName,"chongxin",response);
    35. return "Hello";
    36. }
    37. }

    4、总结

    在开发的过程中还是出现一些问题的,但是已经都解决了,没有及时记录问题,这个有点可惜。

    撸代码的时间还是快乐的,特别是解决问题之后,很开心

    你的点赞是我分享的动力,欢迎点赞评论分享

  • 相关阅读:
    LeetCode中等题之前K个高频单词
    博客资源汇总
    【Vue】Router路由无法跳转问题整理
    关于MP3文件中找不到TAG标签的问题
    腾讯云轻量应用服务器怎么样?来自学生的评价
    Vuex--模块化+命名空间
    中小企业有哪些平台可以引流?SEO搜索流量与推荐信息流流量怎么选?
    mybatis 07: sql标签中 "#{}" 和 "${}" 的作用和比较
    Spring Boot中添加Thymeleaf模板
    MySQL主从数据库搭建
  • 原文地址:https://blog.csdn.net/perfect2011/article/details/128192559