SpringBoot整合Minio实现上传文件的完整步骤记录

目录
  • Minio
  • 安装 Minio
    • 使用docker安装
      • 拉取镜像
      • 启动
      • 使用9000端口 登录控制台
      • 创建存储桶
    • 设置桶权限
    • 创建 Java 客户端
      • 依赖
        • 配置文件
          • 配置文件配置类
            • 创建 minio 客户端
              • 文件地址返回路径实体类
                • 上传文件工具类
                  • 测试上传文件 Controller
                  • 测试上传
                    • 控制台也可以看到上传的视频
                    • 总结

                      Minio

                      上传文件如果不使用云服务的话,需要本地搭建,一般选择 FastDFS 但是 FastDFS 安装比较复杂,今天了解一款安装使用更简单的存储系统 MinIO

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

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

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

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

                      安装 Minio

                      使用docker安装

                      拉取镜像

                      docker pull minio/minio

                      启动

                      docker run -p 9000:9000 -p 9001:9001 -d --name minio -v /opt/docker/minio/data:/data -v /opt/docker/minio/config:/root/.minio -e "MINIO_ROOT_USER=minio" -e "MINIO_ROOT_PASSWORD=minio@123456" minio/minio server /data --console-address ":9000" --address ":9001"

                      使用9000端口 登录控制台

                      创建存储桶

                      设置桶权限

                      创建 Java 客户端

                      依赖

                      <dependencies>
                          <dependency>
                              <groupId>org.springframework.boot</groupId>
                              <artifactId>spring-boot-starter-web</artifactId>
                          </dependency>
                      
                          <dependency>
                              <groupId>org.springframework.boot</groupId>
                              <artifactId>spring-boot-starter-test</artifactId>
                              <scope>test</scope>
                              <exclusions>
                                  <exclusion>
                                      <groupId>org.junit.vintage</groupId>
                                      <artifactId>junit-vintage-engine</artifactId>
                                  </exclusion>
                              </exclusions>
                          </dependency>
                      
                          <dependency>
                              <groupId>org.springframework.boot</groupId>
                              <artifactId>spring-boot-configuration-processor</artifactId>
                              <optional>true</optional>
                          </dependency>
                      
                      
                          <dependency>
                              <groupId>org.projectlombok</groupId>
                              <artifactId>lombok</artifactId>
                              <optional>true</optional>
                          </dependency>
                      
                          <!-- minio依赖       -->
                          <dependency>
                              <groupId>io.minio</groupId>
                              <artifactId>minio</artifactId>
                              <version>8.2.1</version>
                          </dependency>
                      
                          <!-- hutool工具类       -->
                          <dependency>
                              <groupId>cn.hutool</groupId>
                              <artifactId>hutool-all</artifactId>
                              <version>5.1.2</version>
                          </dependency>
                      
                          <!-- 压缩图片       -->
                          <dependency>
                              <groupId>net.coobird</groupId>
                              <artifactId>thumbnailator</artifactId>
                              <version>0.4.8</version>
                          </dependency>
                      
                      
                          <!--    工具类依赖    -->
                          <dependency>
                              <groupId>org.apache.commons</groupId>
                              <artifactId>commons-lang3</artifactId>
                              <version>3.12.0</version>
                          </dependency>
                      
                          <dependency>
                              <groupId>com.github.davidcarboni</groupId>
                              <artifactId>encrypted-</artifactId>
                              <version>1.0.0</version>
                          </dependency>
                      </dependencies>

                      配置文件

                      spring:
                        application:
                          name: minio-demo
                        servlet:
                          multipart:
                            max-file-size: 20MB
                            max-request-size: 200MB
                      server:
                        port: 8088
                      
                      minio:
                        endpoint: http://你的ip:9001
                        accessKey: minio
                        secretKey: minio@123456
                        nginxHost: http://你的域名

                      配置文件配置类

                      package com.sqm.minio_demo.config;
                      
                      import lombok.Data;
                      import org.springframework.boot.context.properties.ConfigurationProperties;
                      import org.springframework.stereotype.Component;
                      
                      @ConfigurationProperties(prefix = "minio")
                      @Component
                      @Data
                      public class MinioProperties {
                          /**
                           * 连接地址
                           */
                          private String endpoint;
                          /**
                           * 用户名
                           */
                          private String accessKey;
                          /**
                           * 密码
                           */
                          private String secretKey;
                          /**
                           * 域名
                           */
                          private String nginxHost;
                      }

                      创建 minio 客户端

                      package com.sqm.minio_demo.config;
                      
                      import io.minio.MinioClient;
                      import org.springframework.beans.factory.annotation.Autowired;
                      import org.springframework.boot.context.properties.EnableConfigurationProperties;
                      import org.springframework.context.annotation.Bean;
                      import org.springframework.context.annotation.Configuration;
                      
                      @Configuration
                      @EnableConfigurationProperties(MinioProperties.class)
                      public class MinioConfig {
                      
                          @Autowired
                          private MinioProperties minioProperties;
                      
                          @Bean
                          public MinioClient minioClient(){
                              return MinioClient.builder()
                                      .endpoint(minioProperties.getEndpoint())
                                      .credentials(minioProperties.getAccessKey(),minioProperties.getSecretKey())
                                      .build();
                          }
                      }

                      文件地址返回路径实体类

                      package com.sqm.minio_demo.entity;
                      
                      import lombok.AllArgsConstructor;
                      import lombok.Data;
                      import lombok.NoArgsConstructor;
                      
                      @Data
                      @NoArgsConstructor
                      @AllArgsConstructor
                      public class UploadResponse {
                      
                          private String minIoUrl;
                      
                          private String nginxUrl;
                      }

                      上传文件工具类

                      package com.sqm.minio_demo.util;
                      
                      import cn.hutool.core.date.DateUtil;
                      import com.sqm.minio_demo.config.MinioProperties;
                      import com.sqm.minio_demo.entity.UploadResponse;
                      import io.minio.*;
                      import io.minio.errors.*;
                      import io.minio.messages.Bucket;
                      import lombok.extern.slf4j.Slf4j;
                      import net.coobird.thumbnailator.Thumbnails;
                      
                      
                      import org.apache.commons.fileupload.FileItem;
                      
                      import org.apache.commons.fileupload.FileItemFactory;
                      import org.apache.commons.fileupload.disk.DiskFileItemFactory;
                      import org.springframework.beans.factory.annotation.Autowired;
                      import org.springframework.stereotype.Component;
                      import org.springframework.web.multipart.MultipartFile;
                      import org.springframework.web.multipart.commons.CommonsMultipartFile;
                      
                      import java.io.File;
                      import java.io.IOException;
                      import java.io.InputStream;
                      import java.io.OutputStream;
                      import java.security.InvalidKeyException;
                      import java.security.NoSuchAlgorithmException;
                      import java.util.List;
                      import java.util.Optional;
                      import java.util.Random;
                      
                      @Component
                      @Slf4j
                      public class MinioUtil {
                      
                          @Autowired
                          private MinioProperties minioProperties;
                      
                          @Autowired
                          private MinioClient minioClient;
                      
                          private final Long maxSize = (long) (1024 * 1024);
                      
                          /**
                           * 创建bucket
                           */
                          public void createBucket(String bucketName) throws Exception {
                              if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                                  minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                              }
                          }
                      
                          /**
                           * 上传文件
                           */
                          public UploadResponse uploadFile(MultipartFile file, String bucketName) throws Exception {
                              //判断文件是否为空
                              if (null == file || 0 == file.getSize()) {
                                  return null;
                              }
                              //判断存储桶是否存在  不存在则创建
                              createBucket(bucketName);
                              //文件名
                              String originalFilename = file.getOriginalFilename();
                              //新的文件名 = 时间戳_随机数.后缀名
                              assert originalFilename != null;
                              long now = System.currentTimeMillis() / 1000;
                              String fileName = DateUtil.format(DateUtil.date(),"yyyyMMdd")+"_"+ now + "_" + new Random().nextInt(1000) +
                                      originalFilename.substring(originalFilename.lastIndexOf("."));
                              //开始上传
                              log.info("file压缩前大小:{}",file.getSize());
                              if (file.getSize() > maxSize) {
                                  FileItemFactory fileItemFactory = new DiskFileItemFactory();
                                  FileItem fileItem = fileItemFactory.createItem(fileName, "text/plain", true, fileName);
                                  OutputStream outputStream = fileItem.getOutputStream();
                                  Thumbnails.of(file.getInputStream()).scale(1f).outputFormat(originalFilename.substring(originalFilename.lastIndexOf(".")+1)).outputQuality(0.25f).toOutputStream(outputStream);
                                  file = new CommonsMultipartFile(fileItem);
                              }
                              log.info("file压缩后大小:{}",file.getSize());
                              minioClient.putObject(
                                      PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
                                              file.getInputStream(), file.getSize(), -1)
                                              .contentType(file.getContentType())
                                              .build());
                              String url = minioProperties.getEndpoint() + "/" + bucketName + "/" + fileName;
                              String urlHost = minioProperties.getNginxHost() + "/" + bucketName + "/" + fileName;
                              return new UploadResponse(url, urlHost);
                          }
                      
                      
                          /**
                           * 获取全部bucket
                           *
                           * @return
                           */
                          public List<Bucket> getAllBuckets() throws Exception {
                              return minioClient.listBuckets();
                          }
                      
                          /**
                           * 根据bucketName获取信息
                           *
                           * @param bucketName bucket名称
                           */
                          public Optional<Bucket> getBucket(String bucketName) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidResponseException, InternalException, ErrorResponseException, ServerException, XmlParserException, ServerException {
                              return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
                          }
                      
                          /**
                           * 根据bucketName删除信息
                           *
                           * @param bucketName bucket名称
                           */
                          public void removeBucket(String bucketName) throws Exception {
                              minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
                          }
                      
                          /**
                           * 获取⽂件外链
                           *
                           * @param bucketName bucket名称
                           * @param objectName ⽂件名称
                           * @param expires    过期时间 <=7
                           * @return url
                           */
                          public String getObjectURL(String bucketName, String objectName, Integer expires) throws Exception {
                              return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).expiry(expires).build());
                          }
                      
                          /**
                           * 获取⽂件
                           *
                           * @param bucketName bucket名称
                           * @param objectName ⽂件名称
                           * @return ⼆进制流
                           */
                          public InputStream getObject(String bucketName, String objectName) throws Exception {
                              return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
                          }
                      
                          /**
                           * 上传⽂件
                           *
                           * @param bucketName bucket名称
                           * @param objectName ⽂件名称
                           * @param stream     ⽂件流
                           * @throws Exception https://docs.minio.io/cn/java-minioClient-api-reference.html#putObject
                           */
                          public void putObject(String bucketName, String objectName, InputStream stream) throws
                                  Exception {
                              minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, stream.available(), -1).contentType(objectName.substring(objectName.lastIndexOf("."))).build());
                          }
                      
                          /**
                           * 上传⽂件
                           *
                           * @param bucketName  bucket名称
                           * @param objectName  ⽂件名称
                           * @param stream      ⽂件流
                           * @param size        ⼤⼩
                           * @param contextType 类型
                           * @throws Exception https://docs.minio.io/cn/java-minioClient-api-reference.html#putObject
                           */
                          public void putObject(String bucketName, String objectName, InputStream stream, long
                                  size, String contextType) throws Exception {
                              minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, size, -1).contentType(contextType).build());
                          }
                      
                          /**
                           * 获取⽂件信息
                           *
                           * @param bucketName bucket名称
                           * @param objectName ⽂件名称
                           * @throws Exception https://docs.minio.io/cn/java-minioClient-api-reference.html#statObject
                           */
                          public StatObjectResponse getObjectInfo(String bucketName, String objectName) throws Exception {
                              return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
                          }
                      
                          /**
                           * 删除⽂件
                           *
                           * @param bucketName bucket名称
                           * @param objectName ⽂件名称
                           * @throws Exception https://docs.minio.io/cn/java-minioClient-apireference.html#removeObject
                           */
                          public void removeObject(String bucketName, String objectName) throws Exception {
                              minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
                          }
                      
                      
                          /***
                           * 上传视频
                           * @param file
                           * @param bucketName
                           * @return
                           * @throws Exception
                           */
                          public UploadResponse uploadVideo(MultipartFile file, String bucketName) throws Exception {
                              //判断文件是否为空
                              if (null == file || 0 == file.getSize()) {
                                  return null;
                              }
                              //判断存储桶是否存在  不存在则创建
                              createBucket(bucketName);
                              //文件名
                              String originalFilename = file.getOriginalFilename();
                              //新的文件名 = 时间戳_随机数.后缀名
                              assert originalFilename != null;
                              long now = System.currentTimeMillis() / 1000;
                              String fileName = DateUtil.format(DateUtil.date(),"yyyyMMdd")+"_"+ now + "_" + new Random().nextInt(1000) +
                                      originalFilename.substring(originalFilename.lastIndexOf("."));
                              //开始上传
                              log.info("file大小:{}",file.getSize());
                              minioClient.putObject(
                                      PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
                                              file.getInputStream(), file.getSize(), -1)
                                              .contentType("video/mp4")
                                              .build());
                              String url = minioProperties.getEndpoint() + "/" + bucketName + "/" + fileName;
                              String urlHost = minioProperties.getNginxHost() + "/" + bucketName + "/" + fileName;
                              return new UploadResponse(url, urlHost);
                          }
                      }

                      测试上传文件 Controller

                      package com.sqm.minio_demo.controller;
                      
                      import com.sqm.minio_demo.entity.ResultData;
                      import com.sqm.minio_demo.entity.UploadResponse;
                      import com.sqm.minio_demo.util.MinioUtil;
                      import lombok.extern.slf4j.Slf4j;
                      import org.springframework.beans.factory.annotation.Autowired;
                      import org.springframework.web.bind.annotation.PostMapping;
                      import org.springframework.web.bind.annotation.RequestParam;
                      import org.springframework.web.bind.annotation.RestController;
                      import org.springframework.web.multipart.MultipartFile;
                      
                      @RestController
                      @Slf4j
                      public class TestController {
                      
                          @Autowired
                          private MinioUtil minioUtil;
                      
                          /**
                           * @author: xx
                           * @date: 2025/5/25 15:32
                           * @description: 上传文件
                           */
                          @PostMapping("/upload")
                          public ResultData minioUpload(@RequestParam(value = "file") MultipartFile file){
                              UploadResponse response = null;
                              try {
                                  response = minioUtil.uploadFile(file, "bucket01");
                              } catch (Exception e) {
                                  log.error("上传失败",e);
                              }
                              return ResultData.ok(response);
                          }
                      
                          /**
                           * @author: xx
                           * @date: 2025/5/25 15:32
                           * @description: 上传视频
                           */
                          @PostMapping("/uploadVideo")
                          public ResultData uploadVideo(@RequestParam(value = "file") MultipartFile file){
                              UploadResponse response = null;
                              try {
                                  response = minioUtil.uploadVideo(file, "video-test");
                              } catch (Exception e) {
                                  log.error("上传失败",e);
                              }
                              return ResultData.ok(response);
                          }
                      }

                      测试上传

                      控制台也可以看到上传的视频

                      总结

                      本文转自网络,如有侵权请联系客服删除。