• SpringBoot + minio实现分片上传、秒传、续传


    MinIO是一个基于Go实现的高性能、兼容S3协议的对象存储。它采用GNU AGPL v3开源协议,项目地址是https://github.com/minio/minio。

    引用官网:

    MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储。它与Amazon S3云存储服务兼容。使用MinIO构建用于机器学习,分析和应用程序数据工作负载的高性能基础架构。

    官网地址:

    MinIO | High Performance, Kubernetes Native Object Storage 

    文档地址:

    MinIO Object Storage for Kubernetes — MinIO Object Storage for Kubernetes 

    一. 使用docker 搭建minio 服务 

    GNU / Linux和macOS

    1. docker run -p 9000:9000 \
    2. --name minio1 \
    3. -v /mnt/data:/data \
    4. -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \
    5. -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
    6. minio/minio server /data

    windows

    1. docker run -p 9000:9000 \
    2. --name minio1 \
    3. -v D:\data:/data \
    4. -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \
    5. -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
    6. minio/minio server /data
    • MINIO_ROOT_USER:为用户key

    • MINIO_ROOT_PASSWORD:为用户密钥

    以上搭建的都是单机版的。想要了解分布式 的方式请查看官网文档。

    这就是在win的docker上运行的。

    当启动后在浏览器访问http://localhost:9000就可以访问minio的图形化界面了,如图所示:

     

    二. 下面开始搭建springboot 环境 

    初始化一个springboot项目大家都会,这里不多做介绍。

    主要是介绍需要引入的依赖:

    1. org.springframework.boot
    2. spring-boot-starter-thymeleaf
    3. io.minio
    4. minio
    5. 8.2.1
    6. org.projectlombok
    7. lombok
    8. true

    依赖可以官方文档里找:https://docs.min.io/docs/java-client-quickstart-guide.html

    下面介绍配置文件:

    1. spring:
    2. servlet:
    3. multipart:
    4. max-file-size: 10MB
    5. max-request-size: 10MB
    6. #minio配置
    7. minio:
    8. access-key: AKIAIOSFODNN7EXAMPLE #key就是docker初始化是设置的,密钥相同
    9. secret-key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    10. url: http://localhost:9000
    11. bucket-name: wdhcr
    12. thymeleaf:
    13. cache: false

     

    创建minio的配置类:

    1. @Configuration
    2. @ConfigurationProperties(prefix = "spring.minio")
    3. @Data
    4. public class MinioConfiguration {
    5. private String accessKey;
    6. private String secretKey;
    7. private String url;
    8. private String bucketName;
    9. @Bean
    10. public MinioClient minioClient() {
    11. return MinioClient.builder()
    12. .endpoint(url)
    13. .credentials(accessKey, secretKey)
    14. .build();
    15. }
    16. }

    使用配置属性绑定进行参数绑定,并初始化一个minio client对象放入容器中。

    下面就是我封装的minio client 操作minio的简单方法的组件。

    1. @Component
    2. public class MinioComp {
    3. @Autowired
    4. private MinioClient minioClient;
    5. @Autowired
    6. private MinioConfiguration configuration;
    7. /**
    8. * @description: 获取上传临时签名
    9. */
    10. public Map getPolicy(String fileName, ZonedDateTime time) {
    11. PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);
    12. postPolicy.addEqualsCondition("key", fileName);
    13. try {
    14. Map map = minioClient.getPresignedPostFormData(postPolicy);
    15. HashMap map1 = new HashMap<>();
    16. map.forEach((k,v)->{
    17. map1.put(k.replaceAll("-",""),v);
    18. });
    19. map1.put("host",configuration.getUrl()+"/"+configuration.getBucketName());
    20. return map1;
    21. } catch (ErrorResponseException e) {
    22. e.printStackTrace();
    23. } catch (InsufficientDataException e) {
    24. e.printStackTrace();
    25. } catch (InternalException e) {
    26. e.printStackTrace();
    27. } catch (InvalidKeyException e) {
    28. e.printStackTrace();
    29. } catch (InvalidResponseException e) {
    30. e.printStackTrace();
    31. } catch (IOException e) {
    32. e.printStackTrace();
    33. } catch (NoSuchAlgorithmException e) {
    34. e.printStackTrace();
    35. } catch (ServerException e) {
    36. e.printStackTrace();
    37. } catch (XmlParserException e) {
    38. e.printStackTrace();
    39. }
    40. return null;
    41. }
    42. /**
    43. * @description: 获取上传文件的url
    44. */
    45. public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit) {
    46. try {
    47. return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
    48. .method(method)
    49. .bucket(configuration.getBucketName())
    50. .object(objectName)
    51. .expiry(time, timeUnit).build());
    52. } catch (ErrorResponseException e) {
    53. e.printStackTrace();
    54. } catch (InsufficientDataException e) {
    55. e.printStackTrace();
    56. } catch (InternalException e) {
    57. e.printStackTrace();
    58. } catch (InvalidKeyException e) {
    59. e.printStackTrace();
    60. } catch (InvalidResponseException e) {
    61. e.printStackTrace();
    62. } catch (IOException e) {
    63. e.printStackTrace();
    64. } catch (NoSuchAlgorithmException e) {
    65. e.printStackTrace();
    66. } catch (XmlParserException e) {
    67. e.printStackTrace();
    68. } catch (ServerException e) {
    69. e.printStackTrace();
    70. }
    71. return null;
    72. }
    73. /**
    74. * @description: 上传文件
    75. */
    76. public void upload(MultipartFile file, String fileName) {
    77. // 使用putObject上传一个文件到存储桶中。
    78. try {
    79. InputStream inputStream = file.getInputStream();
    80. minioClient.putObject(PutObjectArgs.builder()
    81. .bucket(configuration.getBucketName())
    82. .object(fileName)
    83. .stream(inputStream, file.getSize(), -1)
    84. .contentType(file.getContentType())
    85. .build());
    86. } catch (ErrorResponseException e) {
    87. e.printStackTrace();
    88. } catch (InsufficientDataException e) {
    89. e.printStackTrace();
    90. } catch (InternalException e) {
    91. e.printStackTrace();
    92. } catch (InvalidKeyException e) {
    93. e.printStackTrace();
    94. } catch (InvalidResponseException e) {
    95. e.printStackTrace();
    96. } catch (IOException e) {
    97. e.printStackTrace();
    98. } catch (NoSuchAlgorithmException e) {
    99. e.printStackTrace();
    100. } catch (ServerException e) {
    101. e.printStackTrace();
    102. } catch (XmlParserException e) {
    103. e.printStackTrace();
    104. }
    105. }
    106. /**
    107. * @description: 根据filename获取文件访问地址
    108. */
    109. public String getUrl(String objectName, int time, TimeUnit timeUnit) {
    110. String url = null;
    111. try {
    112. url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
    113. .method(Method.GET)
    114. .bucket(configuration.getBucketName())
    115. .object(objectName)
    116. .expiry(time, timeUnit).build());
    117. } catch (ErrorResponseException e) {
    118. e.printStackTrace();
    119. } catch (InsufficientDataException e) {
    120. e.printStackTrace();
    121. } catch (InternalException e) {
    122. e.printStackTrace();
    123. } catch (InvalidKeyException e) {
    124. e.printStackTrace();
    125. } catch (InvalidResponseException e) {
    126. e.printStackTrace();
    127. } catch (IOException e) {
    128. e.printStackTrace();
    129. } catch (NoSuchAlgorithmException e) {
    130. e.printStackTrace();
    131. } catch (XmlParserException e) {
    132. e.printStackTrace();
    133. } catch (ServerException e) {
    134. e.printStackTrace();
    135. }
    136. return url;
    137. }
    138. }

    简单说明:

    • 使用MultipartFile接收前端文件流,再上传到minio。

    • 构建一个formData的签名数据,给前端,让前端之前上传到minio。

    • 构建一个可以上传的临时URL给前端,前端通过携带文件请求该URL进行上传。

    • 使用filename请求服务端获取临时访问文件的URL。(最长时间为7 天,想要永久性访问,需要其他设置,这里不做说明。)

    下面展示页面html,使用的是VUE+element-ui进行渲染。

    1. "UTF-8">
    2. "stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    3. 上传图片
    4. "app">
    5. "2">
    6. "8">
    7. "div-center-class">
    8. "">
    9. 传统上传

    10. class="upload-demo"
    11. action="#"
    12. drag
    13. :http-request="uploadHandle">
    14. "el-icon-upload">
    15. "el-upload__text">将文件拖到此处,或点击上传
    16. "el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb
    17. if="imgUrl">
    18. "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">
  • 页面的效果就如上图所示。

    可以分别体验不同的实现效果。

    以上就是使用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