MinioSpringBoot 整合 Minio(案例代码拿来即用)

Posted 杜小舟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MinioSpringBoot 整合 Minio(案例代码拿来即用)相关的知识,希望对你有一定的参考价值。

文章目录

本篇文章只讲解MinIo的基本使用,下面有一些案例代码拿来即用,不过要注意桶和对象这两个概念,对桶和对象这两个概念下面有讲解。

前置工作

需要在某个服务器安装一个Minio的Server服务。

Minio依赖

<dependency>
	<groupId>io.minio</groupId>
	<artifactId>minio</artifactId>
	<version>8.3.0</version>
</dependency>

MinioClient 配置类

yml配置

# minio
minio:
  # 服务地址
  endpoint: http://localhost:9000
  # 账号
  accessKey: minioadmin
  # 密码
  secretKey: minioadmin

Client配置类

这里把MinioClient注入到Bean中,后续使用MinioClient调用Minio的API。

import io.minio.MinioClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@Slf4j
public class MinIoClientConfig 

    @Value("$minio.endpoint")
    private String endpoint;

    @Value("$minio.accessKey")
    private String accessKey;

    @Value("$minio.secretKey")
    private String secretKey;

    /**
     * 注入minio 客户端
     * @return
     */
    @Bean
    public MinioClient minioClient()
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    



Minio 的基本操作

在这里定义一个OSSFileService接口,用来抽象出Minio的具体实现。
在这里要引入一个 桶(bucket) 的概念,这个桶是Minio用来划分不同数据的,你可以理解成文件夹,不过桶在这里有公开和私密的属性,公开的桶可以随便浏览,而私密的则需要给定一个浏览的时间,超过这个浏览的时间就不能再浏览了。

objectName 对象名称:对象名称可以理解成哪个文件夹下,哪个文件,对象名称例如: public/images/111.jpg

OSSFileService

public interface FileService 

    /**
     * 上传文件
     *
     * @param bucketName 存储桶名称
     * @param input 文件流
     * @param objectName 对象名称
     * @param contentType contentType
     * @return
     */
    void uploadFile(String bucketName, InputStream input, String objectName, String contentType);


    /**
     * 根据对象名称获取公共文件访问路径
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     */
    String getUrlByBucketNameAndObjectName(String bucketName, String objectName);


    /**
     * 根据对象名称获取文件访问路径
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @param getUrlTime 访问文件路径时间
     * @param timeUnit 访问时间格式
     * @return
     */
    String getUrlByBucketNameAndObjectNameAndTime(String bucketName, String objectName, int getUrlTime, TimeUnit timeUnit);


    /**
     * 根据对象名称和桶名称删除对象
     *
     * @param bucketName 桶名称
     * @param objectName 对象名称
     * @return
     */
    void remove(String bucketName, String objectName);


@Service
public class OssFileServiceImpl implements OssFileService 

    @Autowired
    private MinioClient minioClient;

    @Override
    public void uploadFile(String bucketName, InputStream input, String objectName, String contentType) 
        try 
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .contentType(contentType)
                            .stream(input, input.available(), -1)
                            .build());
         catch (Exception e) 
            e.printStackTrace();
         finally 
            try 
                input.close();
             catch (IOException e) 
                e.printStackTrace();
            
        
    

    @Override
    public String getUrlByBucketNameAndObjectName(String bucketName, String objectName) 
    	return  this.getUrl(bucketName, objectName, 1, TimeUnit.DAYS);
    

    @Override
    public String getUrlByBucketNameAndObjectNameAndTime(String bucketName, String objectName, int getUrlTime, TimeUnit timeUnit) 
        return this.getUrl(bucketName, objectName, getUrlTime, timeUnit);
    

    @Override
    public void remove(String bucketName, String objectName) 
        try 
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
         catch (Exception e) 
            e.printStackTrace();
        
    


    /**
     * 根据 桶、object、时间 获取文件路径
     *
     * @param bucketName 桶名称
     * @param objectName object
     * @param getUrlTime 时间
     * @param timeUnit 时间格式
     * @return
     */
    private String getUrl(String bucketName, String objectName, int getUrlTime, TimeUnit timeUnit) 
        try 
            return minioClient.getPresignedObjectUrl(
                            GetPresignedObjectUrlArgs.builder()
                                .bucket(bucketName)
                                .object(objectName)
                                .expiry(getUrlTime, timeUnit)
                                .method(Method.GET)
                                .build());
         catch (Exception e) 
            e.printStackTrace();
        
        return null;
    


Springboot 整合minio文件服务教程

首先pom文件引入相关依赖

        <!--minio-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>3.0.10</version>
        </dependency>

springboot配置文件application.yml 里配置minio信息

#minio配置
minio:
  endpoint: http://$minio_host:172.16.10.21:9000/
  accessKey: $minio_user:minioadmin
  secretKey: $minio_pwd:minioadmin
  bucket: $minio_space:spacedata
  http-url: http://$minio_url:172.16.10.21:9000/
  imgSize: 10485760
  fileSize: 1048576000

创建MinioItem字段项目类


import io.minio.messages.Item;
import io.minio.messages.Owner;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.Date;

@Data
public class MinioItem 
    /**对象名称**/
    @ApiModelProperty("对象名称")
    private String objectName;
    /**最后操作时间**/
    @ApiModelProperty("最后操作时间")
    private Date lastModified;
    private String etag;
    /**对象大小**/
    @ApiModelProperty("对象大小")
    private String size;
    private String storageClass;
    private Owner owner;
    /**对象类型:directory(目录)或file(文件)**/
    @ApiModelProperty("对象类型:directory(目录)或file(文件)")
    private String type;

    public MinioItem(String objectName, Date lastModified, String etag, String size, String storageClass, Owner owner, String type) 
        this.objectName = objectName;
        this.lastModified = lastModified;
        this.etag = etag;
        this.size = size;
        this.storageClass = storageClass;
        this.owner = owner;
        this.type = type;
    


    public MinioItem(Item item) 
        this.objectName = item.objectName();
        this.type = item.isDir() ? "directory" : "file";
        this.etag = item.etag();
        long sizeNum = item.objectSize();
        this.size = sizeNum > 0 ? convertFileSize(sizeNum):"0";
        this.storageClass = item.storageClass();
        this.owner = item.owner();
        try 
            this.lastModified = item.lastModified();
        catch(NullPointerException e)
    

    public String convertFileSize(long size) 
        long kb = 1024;
        long mb = kb * 1024;
        long gb = mb * 1024;
        if (size >= gb) 
            return String.format("%.1f GB", (float) size / gb);
         else if (size >= mb) 
            float f = (float) size / mb;
            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
         else if (size >= kb) 
            float f = (float) size / kb;
            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
         else
            return String.format("%d B", size);
        
    

 

创建MinioTemplate模板类


import com.gis.spacedata.domain.dto.minio.MinioItem;
import com.google.common.collect.Lists;
import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.Result;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.FileCopyUtils;
import org.xmlpull.v1.XmlPullParserException;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
@Component
@RequiredArgsConstructor
public class MinioTemplate implements InitializingBean 

    /**
     * minio的路径
     **/
    @Value("$minio.endpoint")
    private String endpoint;

    /**
     * minio的accessKey
     **/
    @Value("$minio.accessKey")
    private String accessKey;

    /**
     * minio的secretKey
     **/
    @Value("$minio.secretKey")
    private String secretKey;

    /**
     * 下载地址
     **/
    @Value("$minio.http-url")
    private String httpUrl;

    @Value("$minio.bucket")
    private String bucket;

    private static MinioClient minioClient;

    @Override
    public void afterPropertiesSet() throws Exception 
        minioClient = new MinioClient(endpoint, accessKey, secretKey);
    

    @SneakyThrows
    public boolean bucketExists(String bucketName) 
        return minioClient.bucketExists(bucketName);
    

    /**
     * 创建bucket
     *
     * @param bucketName bucket名称
     */
    @SneakyThrows
    public void createBucket(String bucketName) 
        if (!bucketExists(bucketName)) 
            minioClient.makeBucket(bucketName);
        
    

    /**
     * 获取全部bucket
     * <p>
     * https://docs.minio.io/cn/java-client-api-reference.html#listBuckets
     */
    @SneakyThrows
    public List<Bucket> getAllBuckets() 
        return minioClient.listBuckets();
    

    /**
     * 根据bucketName获取信息
     *
     * @param bucketName bucket名称
     */
    @SneakyThrows
    public Optional<Bucket> getBucket(String bucketName) 
        return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    

    /**
     * 根据bucketName删除信息
     *
     * @param bucketName bucket名称
     */
    @SneakyThrows
    public void removeBucket(String bucketName) 
        minioClient.removeBucket(bucketName);
    

    /**
     * 根据文件前缀查询文件
     *
     * @param bucketName bucket名称
     * @param prefix     前缀
     * @param recursive  是否递归查询
     * @return MinioItem 列表
     */
    @SneakyThrows
    public List<MinioItem> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) 
        List<MinioItem> objectList = new ArrayList<>();
        Iterable<Result<Item>> objectsIterator = minioClient.listObjects(bucketName, prefix, recursive);
        for (Result<Item> result : objectsIterator) 
            objectList.add(new MinioItem(result.get()));
        
        return objectList;
    

    /**
     * 获取文件外链
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间 <=7
     * @return url
     */
    @SneakyThrows
    public String getObjectURL(String bucketName, String objectName, Integer expires) 
        return minioClient.presignedGetObject(bucketName, objectName, expires);
    

    /**
     * 获取文件外链
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return url
     */
    @SneakyThrows
    public String getObjectURL(String bucketName, String objectName) 
        return minioClient.presignedGetObject(bucketName, objectName);
    

    /**
     * 获取文件url地址
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return url
     */
    @SneakyThrows
    public String getObjectUrl(String bucketName, String objectName) 
        return minioClient.getObjectUrl(bucketName, objectName);
    

    /**
     * 获取文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
     */
    @SneakyThrows
    public InputStream getObject(String bucketName, String objectName) 
        return minioClient.getObject(bucketName, objectName);
    

    /**
     * 上传文件(流下载)
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream     文件流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream) throws Exception 
        String contentType = "application/octet-stream";
        if ("json".equals(objectName.split("\\\\.")[1])) 
            //json格式,C++编译生成文件,需要直接读取
            contentType = "application/json";
        
        minioClient.putObject(bucketName, objectName, stream, stream.available(), contentType);
    

    /**
     * 上传文件
     *
     * @param bucketName  bucket名称
     * @param objectName  文件名称
     * @param stream      文件流
     * @param size        大小
     * @param contextType 类型
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception 
        minioClient.putObject(bucketName, objectName, stream, size, contextType);
    

    /**
     * 获取文件信息
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
     */
    public ObjectStat getObjectInfo(String bucketName, String objectName) throws Exception 
        return minioClient.statObject(bucketName, objectName);
    

    /**
     * 删除文件夹及文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件或文件夹名称
     * @since tarzan LIU
     */
    public void removeObject(String bucketName, String objectName) 
        try 
            if (StringUtils.isNotBlank(objectName)) 
                if (objectName.endsWith(".") || objectName.endsWith("/")) 
                    Iterable<Result<Item>> list = minioClient.listObjects(bucketName, objectName);
                    list.forEach(e -> 
                        try 
                            minioClient.removeObject(bucketName, e.get().objectName());
                         catch (InvalidBucketNameException invalidBucketNameException) 
                            invalidBucketNameException.printStackTrace();
                         catch (NoSuchAlgorithmException noSuchAlgorithmException) 
                            noSuchAlgorithmException.printStackTrace();
                         catch (InsufficientDataException insufficientDataException) 
                            insufficientDataException.printStackTrace();
                         catch (IOException ioException) 
                            ioException.printStackTrace();
                         catch (InvalidKeyException invalidKeyException) 
                            invalidKeyException.printStackTrace();
                         catch (NoResponseException noResponseException) 
                            noResponseException.printStackTrace();
                         catch (XmlPullParserException xmlPullParserException) 
                            xmlPullParserException.printStackTrace();
                         catch (ErrorResponseException errorResponseException) 
                            errorResponseException.printStackTrace();
                         catch (InternalException internalException) 
                            internalException.printStackTrace();
                        
                    );
                
            
         catch (XmlPullParserException e) 
            e.printStackTrace();
        
    

    /**
     * 下载文件夹内容到指定目录
     *
     * @param bucketName bucket名称
     * @param objectName 文件或文件夹名称
     * @param dirPath    指定文件夹路径
     * @since tarzan LIU
     */
    public void downloadTargetDir(String bucketName, String objectName, String dirPath) 
        try 
            if (StringUtils.isNotBlank(objectName)) 
                if (objectName.endsWith(".") || objectName.endsWith("/")) 
                    Iterable<Result<Item>> list = minioClient.listObjects(bucketName, objectName);
                    list.forEach(e -> 
                        try 
                            String url = minioClient.getObjectUrl(bucketName, e.get().objectName());
                            getFile(url, dirPath);
                         catch (InvalidBucketNameException invalidBucketNameException) 
                            invalidBucketNameException.printStackTrace();
                         catch (NoSuchAlgorithmException noSuchAlgorithmException) 
                            noSuchAlgorithmException.printStackTrace();
                         catch (InsufficientDataException insufficientDataException) 
                            insufficientDataException.printStackTrace();
                         catch (IOException ioException) 
                            ioException.printStackTrace();
                         catch (InvalidKeyException invalidKeyException) 
                            invalidKeyException.printStackTrace();
                         catch (NoResponseException noResponseException) 
                            noResponseException.printStackTrace();
                         catch (XmlPullParserException xmlPullParserException) 
                            xmlPullParserException.printStackTrace();
                         catch (ErrorResponseException errorResponseException) 
                            errorResponseException.printStackTrace();
                         catch (InternalException internalException) 
                            internalException.printStackTrace();
                        
                    );
                
            
         catch (XmlPullParserException e) 
            e.printStackTrace();
        
    


    public static void main(String[] args) throws
            NoSuchAlgorithmException, IOException, InvalidKeyException, XmlPullParserException 
        try 
            // 使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象
            MinioClient minioClient = new MinioClient("http://172.16.10.201:9000/", "minioadmin", "minioadmin");

            // 检查存储桶是否已经存在
            boolean isExist = minioClient.bucketExists("spacedata");
            if (isExist) 
                System.out.println("Bucket already exists.");
             else 
                // 创建一个名为asiatrip的存储桶,用于存储照片的zip文件。
                minioClient.makeBucket("spacedata");
            

            // 使用putObject上传一个文件到存储桶中。
            //  minioClient.putObject("spacedata", "测试.jpg", "C:\\\\Users\\\\sundasheng44\\\\Desktop\\\\1.png");

            //  minioClient.removeObject("spacedata", "20200916/8ca27855ba884d7da1496fb96907a759.dwg");
            Iterable<Result<Item>> list = minioClient.listObjects("spacedata", "CompileResult/");
            List<String> list1 = Lists.newArrayList();
            list.forEach(e -> 
                try 
                    list1.add("1");
                    String url = minioClient.getObjectUrl("spacedata", e.get().objectName());
                    System.out.println(url);
                    //getFile(url, "C:\\\\Users\\\\liuya\\\\Desktop\\\\" + e.get().objectName());
                    System.out.println(e.get().objectName());
                    //   minioClient.removeObject("spacedata", e.get().objectName());
                 catch (InvalidBucketNameException invalidBucketNameException) 
                    invalidBucketNameException.printStackTrace();
                 catch (NoSuchAlgorithmException noSuchAlgorithmException) 
                    noSuchAlgorithmException.printStackTrace();
                 catch (InsufficientDataException insufficientDataException) 
                    insufficientDataException.printStackTrace();
                 catch (IOException ioException) 
                    ioException.printStackTrace();
                 catch (InvalidKeyException invalidKeyException) 
                    invalidKeyException.printStackTrace();
                 catch (NoResponseException noResponseException) 
                    noResponseException.printStackTrace();
                 catch (XmlPullParserException xmlPullParserException) 
                    xmlPullParserException.printStackTrace();
                 catch (ErrorResponseException errorResponseException) 
                    errorResponseException.printStackTrace();
                 catch (InternalException internalException) 
                    internalException.printStackTrace();
                
            );
            System.out.println(list1.size());
         catch (MinioException e) 
            System.out.println("Error occurred: " + e);
        
    

    /**
     * 文件流下载(原始文件名)
     *
     * @author sunboqiang
     * @date 2020/10/22
     */
    public ResponseEntity<byte[]> fileDownload(String url, String fileName, HttpServletRequest request) 
        return this.downloadMethod(url, fileName, request);
    

    private File getFile(String url, String fileName) 
        InputStream in = null;
        // 创建文件
        String dirPath = fileName.substring(0, fileName.lastIndexOf("/"));
        File dir = new File(dirPath);
        if (!dir.exists()) 
            dir.mkdirs();
        
        File file = new File(fileName);
        try 
            URL url1 = new URL(url);
            in = url1.openStream();
            // 输入流转换为字节流
            byte[] buffer = FileCopyUtils.copyToByteArray(in);
            // 字节流写入文件
            FileCopyUtils.copy(buffer, file);
            // 关闭输入流
            in.close();
         catch (IOException e) 
            log.error("文件获取失败:" + e);
            return null;
         finally 
            try 
                in.close();
             catch (IOException e) 
                log.error("", e);
            
        
        return file;
    

    public ResponseEntity<byte[]> downloadMethod(String url, String fileName, HttpServletRequest request) 
        HttpHeaders heads = new HttpHeaders();
        heads.add(HttpHeaders.CONTENT_TYPE, "application/octet-stream; charset=utf-8");
        try 
            if (request.getHeader("User-Agent").toLowerCase().indexOf("firefox") > 0) 
                // firefox浏览器
                fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1");
             else if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) 
                // IE浏览器
                fileName = URLEncoder.encode(fileName, "UTF-8");
             else if (request.getHeader("User-Agent").toUpperCase().indexOf("EDGE") > 0) 
                // WIN10浏览器
                fileName = URLEncoder.encode(fileName, "UTF-8");
             else if (request.getHeader("User-Agent").toUpperCase().indexOf("CHROME") > 0) 
                // 谷歌
                fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1");
             else 
                //万能乱码问题解决
                fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            
         catch (UnsupportedEncodingException e) 
            // log.error("", e);
        
        heads.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName);
        try 
            //InputStream in = new FileInputStream(file);
            URL url1 = new URL(url);
            InputStream in = url1.openStream();
            // 输入流转换为字节流
            byte[] buffer = FileCopyUtils.copyToByteArray(in);
            ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(buffer, heads, HttpStatus.OK);
            //file.delete();
            return responseEntity;
         catch (Exception e) 
            log.error("", e);
        
        return null;
    

创建 FilesMinioService 服务类


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gis.spacedata.common.constant.response.ResponseCodeConst;
import com.gis.spacedata.common.domain.ResponseDTO;
import com.gis.spacedata.domain.dto.file.vo.UploadVO;
import com.gis.spacedata.domain.dto.minio.MinioItem;
import com.gis.spacedata.domain.entity.file.FileEntity;
import com.gis.spacedata.enums.file.FileServiceTypeEnum;
import com.gis.spacedata.handler.SmartBusinessException;
import com.gis.spacedata.mapper.file.FileDao;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springblade.core.tool.utils.FileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class FilesMinioService extends ServiceImpl<FileDao, FileEntity> 

    @Autowired
    private MinioTemplate minioTemplate;

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    /**
     * 图片大小限制
     **/
    @Value("#$minio.imgSize")
    private Long imgSize;

    /**
     * 文件大小限制
     **/
    @Value("#$minio.fileSize")
    private Long fileSize;

    @Value("$minio.bucket")
    private String bucket;

    /**
     * 下载地址
     **/
    @Value("$minio.http-url")
    private String httpUrl;

    /**
     * 判断是否图片
     */
    private boolean isImage(String fileName) 
        //设置允许上传文件类型
        String suffixList = "jpg,gif,png,ico,bmp,jpeg";
        // 获取文件后缀
        String suffix = fileName.substring(fileName.lastIndexOf(".")
                + 1);
        return suffixList.contains(suffix.trim().toLowerCase());
    

    /**
     * 验证文件大小
     *
     * @param upfile
     * @param fileName 文件名称
     * @throws Exception
     */
    private void fileCheck(MultipartFile upfile, String fileName) throws Exception 
        Long size = upfile.getSize();
        if (isImage(fileName)) 
            if (size > imgSize) 
                throw new Exception("上传对图片大于:" + (imgSize / 1024 / 1024) + "M限制");
            
         else 
            if (size > fileSize) 
                throw new Exception("上传对文件大于:" + (fileSize / 1024 / 1024) + "M限制");
            
        
    

    /**
     * 文件上传
     *
     * @author sunboqiang
     * @date 2020/9/9
     */
    public ResponseDTO<UploadVO> fileUpload(MultipartFile upfile) throws IOException 
        String originalFileName = upfile.getOriginalFilename();
        try 
            fileCheck(upfile, originalFileName);
         catch (Exception e) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR, e.getMessage());
        
        if (StringUtils.isBlank(originalFileName)) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "文件名称不能为空");
        
        UploadVO vo = new UploadVO();
        String url;
        //获取文件md5,查找数据库,如果有,则不需要上传了
        String md5 = DigestUtils.md5Hex(upfile.getInputStream());
        QueryWrapper<FileEntity> query = new QueryWrapper<>();
        query.lambda().eq(FileEntity::getMd5, md5);
        query.lambda().eq(FileEntity::getStorageType, FileServiceTypeEnum.MINIO_OSS.getLocationType());
        FileEntity fileEntity = baseMapper.selectOne(query);
        if (null != fileEntity) 
            //url = minioTemplate.getObjectURL(bucket,fileEntity.getFileName());
            vo.setId(fileEntity.getId());
            vo.setFileName(originalFileName);
            vo.setUrl(httpUrl + fileEntity.getFileUrl());
            vo.setNewFileName(fileEntity.getFileName());
            vo.setFileSize(upfile.getSize());
            vo.setFileLocationType(FileServiceTypeEnum.MINIO_OSS.getLocationType());
            log.info("文件已上传,直接获取");
            return ResponseDTO.succData(vo);
        
        //拼接文件名
        String fileName = generateFileName(originalFileName);
        try 
            // 检查存储桶是否已经存在
            boolean isExist = minioTemplate.bucketExists(bucket);
            if (isExist) 
                log.info("Bucket already exists.");
             else 
                // 创建一个名为asiatrip的存储桶,用于存储照片的zip文件。
                minioTemplate.createBucket(bucket);
            
            // 使用putObject上传一个文件到存储桶中。
            minioTemplate.putObject(bucket, fileName, upfile.getInputStream());
            log.info("上传成功.");
            //生成一个外部链接
            //url = minioTemplate.getObjectURL(bucket,fileName);
            //已经设置永久链接,直接获取
            url = httpUrl + bucket + "/" + fileName;
            fileEntity = new FileEntity();
            fileEntity.setStorageType(FileServiceTypeEnum.MINIO_OSS.getLocationType());
            fileEntity.setFileName(fileName);
            fileEntity.setOriginalFileName(originalFileName);
            fileEntity.setFileUrl(bucket + "/" + fileName);
            fileEntity.setFileSize(upfile.getSize());
            fileEntity.setMd5(md5);
            baseMapper.insert(fileEntity);
         catch (Exception e) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR, "上传失败!");
        
        vo.setFileName(originalFileName);
        vo.setId(fileEntity.getId());
        vo.setUrl(url);
        vo.setNewFileName(fileName);
        vo.setFileSize(upfile.getSize());
        vo.setFileLocationType(FileServiceTypeEnum.MINIO_OSS.getLocationType());

        return ResponseDTO.succData(vo);
    

    /**
     * 生成文件名字
     * 当前年月日时分秒 +32位 uuid + 文件格式后缀
     *
     * @param originalFileName
     * @return String
     */
    private String generateFileName(String originalFileName) 
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String fileType = originalFileName.substring(originalFileName.lastIndexOf("."));
        return time + "/" + uuid + fileType;
    

    /**
     * 文件上传(不做重复校验)
     *
     * @author sunboqiang
     * @date 2020/9/25
     */
    public ResponseDTO<UploadVO> fileUploadRep(MultipartFile upfile) throws IOException 
        String originalFileName = upfile.getOriginalFilename();
        try 
            fileCheck(upfile, originalFileName);
         catch (Exception e) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR, e.getMessage());
        
        if (StringUtils.isBlank(originalFileName)) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "文件名称不能为空");
        
        UploadVO vo = new UploadVO();
        String url;
        //获取文件md5
        FileEntity fileEntity = new FileEntity();
        //拼接文件名
        String fileName = generateFileName(originalFileName);
        try 
            // 检查存储桶是否已经存在
            boolean isExist = minioTemplate.bucketExists(bucket);
            if (isExist) 
                log.info("Bucket already exists.");
             else 
                // 创建一个名为asiatrip的存储桶,用于存储照片的zip文件。
                minioTemplate.createBucket(bucket);
            
            // 使用putObject上传一个文件到存储桶中。
            minioTemplate.putObject(bucket, fileName, upfile.getInputStream());
            log.info("上传成功.");
            //生成一个外部链接
            //url = minioTemplate.getObjectURL(bucket,fileName);
            //已经设置永久链接,直接获取
            url = httpUrl + bucket + "/" + fileName;
            fileEntity.setStorageType(FileServiceTypeEnum.MINIO_OSS.getLocationType());
            fileEntity.setFileName(fileName);
            fileEntity.setOriginalFileName(originalFileName);
            fileEntity.setFileUrl(bucket + "/" + fileName);
            fileEntity.setFileSize(upfile.getSize());
            baseMapper.insert(fileEntity);
         catch (Exception e) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR, "上传失败!");
        
        vo.setFileName(originalFileName);
        vo.setId(fileEntity.getId());
        vo.setUrl(url);
        vo.setNewFileName(fileName);
        vo.setFileSize(upfile.getSize());
        vo.setFileLocationType(FileServiceTypeEnum.MINIO_OSS.getLocationType());

        return ResponseDTO.succData(vo);
    

    /**
     * 文件流上传(不存数据库)
     *
     * @author sunboqiang
     * @date 2020/9/25
     */
    public ResponseDTO<UploadVO> uploadStream(InputStream inputStream, String originalFileName) 
        UploadVO vo = new UploadVO();
        String url;
        //文件名
        String fileName = originalFileName;
        try 
            // 检查存储桶是否已经存在
            boolean isExist = minioTemplate.bucketExists(bucket);
            if (isExist) 
                log.info("Bucket already exists.");
             else 
                // 创建一个名为asiatrip的存储桶,用于存储照片的zip文件。
                minioTemplate.createBucket(bucket);
            
            // 使用putObject上传一个文件到存储桶中。
            minioTemplate.putObject(bucket, fileName, inputStream);
            log.info("上传成功.");
            //生成一个外部链接
            //url = minioTemplate.getObjectURL(bucket,fileName);
            //已经设置永久链接,直接获取
            url = httpUrl + bucket + "/" + fileName;
         catch (Exception e) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR, "上传失败!");
        
        vo.setFileName(originalFileName);
        vo.setUrl(url);
        vo.setNewFileName(fileName);
        vo.setFileLocationType(FileServiceTypeEnum.MINIO_OSS.getLocationType());

        return ResponseDTO.succData(vo);
    

    private String generateFileNameTwo(String originalFileName) 
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        return time + "/" + originalFileName;
    

    /**
     * 文件查询
     *
     * @author sunboqiang
     * @date 2020/9/25
     */
    public ResponseDTO<UploadVO> findFileById(Long id) 
        FileEntity fileEntity = baseMapper.selectById(id);
        if (null == fileEntity) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "文件不存在");
        
        UploadVO vo = new UploadVO();
        /*String url = minioTemplate.getObjectURL(bucket,fileEntity.getFileName());
        if(StringUtils.isEmpty(url))
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM,"获取minio 文件url失败!");
        */
        vo.setFileName(fileEntity.getOriginalFileName());
        vo.setUrl(httpUrl + fileEntity.getFileUrl());
        vo.setNewFileName(fileEntity.getFileName());
        vo.setFileSize(fileEntity.getFileSize());
        vo.setFileLocationType(FileServiceTypeEnum.MINIO_OSS.getLocationType());
        return ResponseDTO.succData(vo);
    


    /**
     * 文件流式下载
     *
     * @author sunboqiang
     * @date 2020/10/22
     */
    public ResponseEntity<byte[]> downLoadFile(Long id, HttpServletRequest request) 
        FileEntity fileEntity = baseMapper.selectById(id);
        if (null == fileEntity) 
            throw new SmartBusinessException("文件信息不存在");
        
        if (StringUtils.isEmpty(fileEntity.getFileUrl())) 
            throw new SmartBusinessException("文件url为空");
        
        ResponseEntity<byte[]> stream = minioTemplate.fileDownload(httpUrl + fileEntity.getFileUrl(), fileEntity.getOriginalFileName(), request);
        return stream;
    

    /**
     * 文件删除(通过文件名)
     *
     * @author tarzan Liu
     * @date 2020/11/11
     */
    public ResponseDTO<String> deleteFiles(List<String> fileNames) 
        try 
            for (String fileName : fileNames) 
                minioTemplate.removeObject(bucket, fileName);
            
         catch (Exception e) 
            return ResponseDTO.wrap(ResponseCodeConst.ERROR, e.getMessage());
        
        return ResponseDTO.succ();
    

    /**
     * tarzan LIU
     *
     * @author tarzan Liu
     * @date 2020/11/11
     */
    public ResponseDTO<String> downloadTargetDir(String objectName, String dirPath) 
        minioTemplate.downloadTargetDir(bucket, objectName, dirPath);
        return ResponseDTO.succ();
    

    /**
     * 下载备份编译结果
     *
     * @param dirPath
     * @return @link Boolean
     * @author zhangpeng
     * @date 2021年10月15日
     */
    public Boolean downloadCompile(String dirPath) 
        if (!minioTemplate.bucketExists(bucket)) 
            log.info("Bucket not exists.");
            return true;
        

        List<MinioItem> list = minioTemplate.getAllObjectsByPrefix(bucket, "CompileResult/", true);
        list.forEach(e -> 
            String url = minioTemplate.getObjectUrl(bucket, e.getObjectName());
            InputStream minioStream = minioTemplate.getObject(bucket, e.getObjectName());
            File file = new File(dirPath + url.substring(url.indexOf("CompileResult")-1));
            if (!file.getParentFile().exists()) 
                file.getParentFile().mkdirs();
            
            FileUtil.toFile(minioStream, file);
        );

        log.info("downloadCompile complete.");
        return true;
    

部分操作数据库的相关代码省略,不再展示

创建FilesMinioController 服务接口


import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.gis.spacedata.common.anno.NoNeedLogin;
import com.gis.spacedata.common.domain.ResponseDTO;
import com.gis.spacedata.domain.dto.file.vo.UploadVO;
import com.gis.spacedata.service.file.FilesMinioService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

@Api(tags = "minio文件服务")
@RestController
public class FilesMinioController 

    @Autowired
    private FilesMinioService filesMinioService;


    @ApiOperation(value = "文件上传(md5去重上传) by sunboqiang")
    @PostMapping("/minio/uploadFile/md5")
    @NoNeedLogin
    public ResponseDTO<UploadVO> uploadFile(MultipartFile file) throws IOException 
        return filesMinioService.fileUpload(file);
    

    @ApiOperation(value = "文件上传(不做重复校验) by sunboqiang")
    @PostMapping("/minio/uploadFile/noRepeatCheck")
    public ResponseDTO<UploadVO> fileUploadRep(MultipartFile file) throws IOException 
        return filesMinioService.fileUploadRep(file);
    

    @ApiOperation(value = "文件流上传 by sunboqiang")
    @PostMapping("/minio/uploadFile/stream/fileName")
    public ResponseDTO<UploadVO> uploadStream(InputStream inputStream, @PathVariable("fileName") String fileName) throws IOException 
        return filesMinioService.uploadStream(inputStream, fileName);
    

    @ApiOperation(value = "文件查询(永久链接) by sunboqiang")
    @GetMapping("/minio/getFileUrl/id")
    public ResponseDTO<UploadVO> findFileById(@PathVariable("id") Long id) 
        return filesMinioService.findFileById(id);
    

    @ApiOperation(value = "文件流式下载 by sunboqiang")
    @GetMapping("/minio/downloadFile/stream")
    public ResponseEntity<byte[]> downLoadFile(@RequestParam Long id, HttpServletRequest request) 
        return filesMinioService.downLoadFile(id, request);
    

    @ApiOperation(value = "文件删除(通过文件名) by sunboqiang")
    @PostMapping("/minio/deleteFiles")
    public ResponseDTO<String> deleteFiles(@RequestBody List<String> fileNames) 
        return filesMinioService.deleteFiles(fileNames);
    

windows和linux安装minio服务教程请自行百度。

以上是关于MinioSpringBoot 整合 Minio(案例代码拿来即用)的主要内容,如果未能解决你的问题,请参考以下文章

Minio 整合springboot 开发 实现文件上传

Springboot 整合minio文件服务教程

Springboot 整合minio文件服务教程

SpringBoot 整合MinIO

对象存储服务MinIO安装,编写Starter整合,及永久链接配置

SpringBoot2 整合MinIO中间件,实现文件便捷管理