Spring boot 集成Minio实现文件单文件上传

一:准备工作本机安装Minio客户端

1:官方下载minio客户端工具:https://dl.min.io/server/minio/release/windows-amd64/minio.exe

官网上提供了多种环境安装:https://docs.min.io/cn/,大家可以自己选择。

2:cmd进入命令行,到minio.exe存放目录:执行:minio.exe server D:/minio/Data(PS:Data是我用来存放文件的文件夹,这个随大家选择),执行完之后出现如图:

sentinel 集成Springboot3 springboot集成mina_java

代表安装启动成功。浏览器访问:127.0.0.1:9000,出现如下:

sentinel 集成Springboot3 springboot集成mina_spring_02

使用上图的minioadmin登陆。

sentinel 集成Springboot3 springboot集成mina_文件名_03

体验一下:

新建文件桶:

sentinel 集成Springboot3 springboot集成mina_java_04

sentinel 集成Springboot3 springboot集成mina_文件名_05

sentinel 集成Springboot3 springboot集成mina_文件名_06

可以看到一个img桶已经被创建好了,接下来我们就可以手动上传文件了。

二:代码实现

  • 我们在工程中POM文件中先引入minioCilent的sdk包。
<!-- 引入minio sdk客户端 -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>6.0.8</version>
</dependency>
  • 启动配置文件(application.yml)中添加如下:
spring :
  ## 设置传输文件最大容量,防止上传文件因为容量太大导致上传失败
  servlet:
    multipart:
      maxFileSize: 2000MB
      maxRequestSize: 2000MB
minio:
  ## 以下仅仅本机测试,项目中不同文件肯定肯定存放的位置不一样,所以bocket(桶名也是不固定的)
  url: http://127.0.0.1:9000
  accessKey: minioadmin
  secretKey: minioadmin
  bocket: file
  • 创建MinioConfig配置POJO文件(读取配置文件关于minio配置参数)
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioClientConfig {
    /**
     * minio host
     */
    private String url;

    /**
     * 接入账号
     */
    private String accessKey;

    /**
     * 接入口令
     */
    private String secretKey;

    /**
     * 文件存放桶名
     */
    private String bocket;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getAccessKey() {
        return accessKey;
    }

    public void setAccessKey(String accessKey) {
        this.accessKey = accessKey;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public String getBocket() {
        return bocket;
    }

    public void setBocket(String bocket) {
        this.bocket = bocket;
    }
}
  • 创建工具类
    生成文件服务器上唯一文件名
import java.time.LocalDate;

/**
 * @Author: 张全成
 * 该工具类目前只是生成文件在服务器上唯一文件名
 * 后续会采用雪花算法生成唯一标识,
 * 项目中建议大家自己或者借助平台生成的唯一ID
 * @Date: 2020/5/17 12:22
 * @Version 1.0
 */
public class FileNameUtils {
    public static String getNextId (String prefix) {
        String fileName = "";
        // 生成6位数随机数
        String random = String.valueOf((int) ((Math.random()*9+1)*100000));
        fileName = new StringBuilder().append(prefix).append(LocalDate.now()).append(random).toString();
        return fileName;
    }
}

获取某天年,月,日工具类(生成目录使用)

import java.time.LocalDate;

/**
 * 时间操作工具类
 * @author 张全成
 */
public class TimeUtils {

    /**
     * 获取年月日:
     * @param nowTime
     * @param kind 00:年;01:月:02:日
     * @return
     */
    public static String getCode(LocalDate nowTime,String kind){
        String code = "";
        if ("00".equals(kind)) {
            code = String.valueOf(nowTime.getYear());
        } else if("01".equals(kind)) {
            code = String.valueOf(nowTime.getMonthValue());
        } else if ("02".equals(kind)) {
            code = String.valueOf(nowTime.getDayOfMonth());
        }
        return code;
    }
}

minioClient工具类

import com.zqc.fileprocess.config.MinioClientConfig;
import io.minio.MinioClient;
import io.minio.errors.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * @Author: 张全成
 * @Date: 2020/5/17 13:28
 * @Version 1.0
 */
public class MinioClientUtils {

    private static MinioClient minioClient;

    private static final Logger logger = LoggerFactory.getLogger(MinioClientUtils.class);

    public static Boolean fileUpload(MultipartFile file, String filePath, String suffix, MinioClientConfig minioClientConfig) {
        boolean flag = false;
        // 先判断桶是否存在,如果不存在先创建桶
        try {
            if (!getMinioClient(minioClientConfig).bucketExists(suffix)) {
                getMinioClient(minioClientConfig).makeBucket(suffix);
            }
            // 开始上传文件
            InputStream inputStream = file.getInputStream();
            getMinioClient(minioClientConfig).putObject(suffix,filePath,inputStream,inputStream.available(),file.getContentType());
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    public static MinioClient getMinioClient(MinioClientConfig clientConfig) {
        if (minioClient == null) {
            try {
                minioClient = new MinioClient(clientConfig.getUrl(),clientConfig.getAccessKey(),clientConfig.getSecretKey());
            } catch (Exception e) {
                logger.info("creat minioClient fail");
                e.printStackTrace();
            }
        }
        return minioClient;
    }
}
  • 业务实现类
package com.zqc.fileprocess.service.impl;

import com.zqc.fileprocess.config.MinioClientConfig;
import com.zqc.fileprocess.service.FileProcessService;
import com.zqc.fileprocess.utils.FileNameUtils;
import com.zqc.fileprocess.utils.MinioClientUtils;
import com.zqc.fileprocess.utils.TimeUtils;
import org.aspectj.lang.annotation.Around;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;

/**
 * @Author: 张全成
 * @Date: 2020/5/17 13:24
 * @Version 1.0
 */
@Service
public class FileProcessServiceImpl implements FileProcessService {

    @Autowired
    MinioClientConfig minioClientConfig;

    @Override
    public String fileUpload(MultipartFile file) {
        // 文件名
        String fileName = "";
        // 文件格式
        String prefix = "";
        // 服务器上文件的相对路径
        String filePath = "";
        // 上传成功标识
        boolean flag = false;
        // 获取文件前缀
        int index= file.getOriginalFilename().indexOf(".")+1;
        prefix = file.getOriginalFilename().substring(index);
        fileName = FileNameUtils.getNextId(prefix);
        // 文件相对路径我这边设置成了/桶名/年/月/日/唯一文件名
        LocalDate localDate = LocalDate.now();
        filePath =  new StringBuilder()
                .append("/").append(TimeUtils.getCode(localDate,"00"))
                .append("/").append(TimeUtils.getCode(localDate,"01"))
                .append("/").append(TimeUtils.getCode(localDate,"02"))
                .append("/").append(fileName).append(".").append(prefix).toString();
        flag = MinioClientUtils.fileUpload(file,filePath,prefix,minioClientConfig);
        if (flag){
            return fileName;
        } else {
            return null;
        }
    }
}
  • 测试入口Controller
package com.zqc.fileprocess.controller;

import com.zqc.fileprocess.service.FileProcessService;
import com.zqc.fileprocess.utils.FileNameUtils;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Field;

/**
 * @Author: 张全成
 * @Date: 2020/5/17 12:43
 * @Version 1.0
 */
@RestController
@RequestMapping("/v1/fileProcess")
public class FileProcessController {

    @Autowired
    FileProcessService fileProcessService;

    /**
     * 单文件上传
     * @param file
     * @return 返回文件名,让业务方做记录
     */
    @PostMapping("/upload")
    public String fileUploa(@RequestParam MultipartFile file) {
        String fileName = fileProcessService.fileUpload(file);
        return fileName;
    }
}

三:项目启动测试

  • 启动项目
  • postMan测试

sentinel 集成Springboot3 springboot集成mina_java_07

发送之后可以得到返回参数是上传文件在文件服务器上文件名。

  • 查看文件是否上传,两种方式确认:
    1:在本机minio.exe文件所在目录中找到Data目录(就是安装启动时后面的目录,加粗部分:minio.exe server D:/minio/Data

sentinel 集成Springboot3 springboot集成mina_spring_08

2:登陆127.0.0.1:9000,查看

sentinel 集成Springboot3 springboot集成mina_spring_09

以上就是spring boot 集成minio实现单文件上传demo,具体代码git地址:https://github.com/Thresh6300/fileProcess.git。后续会给大家提供单文件下载,批量上传,批量下载。至于没有文件删除这里解释一下:一般我们删除都是逻辑删除(就是数据库中将这条文件记录状态设置为删除状态),很少公司要求真正的删除文件服务器上的文件。