Minio入门系列【7】Spring Boot集成Minio

1 前言

之前介绍了如何使用Minio提供的JAVA SDK进行上传和下载文件,在此基础上,我们可以使用spring boot集成Minio JAVA SDK,添加自动配置、装配、客户端管理等功能,简化开发

2 Spring Boot集成Minio

2.1 环境搭建

首先我们搭建一个spring boot基础工程,引入以下依赖

xml 复制代码
    <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>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.minio/minio -->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.3.1</version>
        </dependency>
        <dependency>
            <groupId>me.tongfei</groupId>
            <artifactId>progressbar</artifactId>
            <version>0.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.2</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>

2.2 操作模板类

在spring中,提供了很多集成第三方的操作模板类,比如RedisTemplate、RestTemplate等等,我们可以参照这些,提供一个minio SDK的集成模板类,这样在使用API时就比较方便了。

首先需要创建一个OSS文件对象,上传文件成功后,我们需要将文件信息返回给前端

java 复制代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;

/**
 * @author wuKeFan
 * @date 2020/9/10
 */
@RefreshScope
@Configuration
public class OssConfig {

    @Value("${biz.oss.endpoint}")
    private String endpoint;
    @Value("${biz.oss.bucket}")
    private String bucket;
    @Value("${biz.oss.access-key-id}")
    private String accessKeyId;
    @Value("${biz.oss.access-key-secret}")
    private String accessKeySecret;
    @Value("${biz.oss.type}")
    private Integer ossType;

    /**
     * 最大上传长度单位m,默认20M
     */
    @Value("${biz.oss.maxLength:20}")
    private Integer maxLength;

    public String getAccessId() {
        return accessKeyId;
    }

    public String getBucket() {
        return bucket;
    }

    public String getEndpoint() {
        return endpoint;
    }

    public Integer getMaxLength() {
        return maxLength;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public void setBucket(String bucket) {
        this.bucket = bucket;
    }

    public String getAccessKeyId() {
        return accessKeyId;
    }

    public void setAccessKeyId(String accessKeyId) {
        this.accessKeyId = accessKeyId;
    }

    public String getAccessKeySecret() {
        return accessKeySecret;
    }

    public void setAccessKeySecret(String accessKeySecret) {
        this.accessKeySecret = accessKeySecret;
    }

    public void setMaxLength(Integer maxLength) {
        this.maxLength = maxLength;
    }

    public Integer getOssType() {
        return ossType;
    }

    public void setOssType(Integer ossType) {
        this.ossType = ossType;
    }
}
java 复制代码
import com.mall4j.cloud.common.exception.Mall4cloudException;
import com.mall4j.cloud.common.response.ResponseEnum;
import io.minio.*;
import io.minio.http.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author wuKeFan
 */
@Component
public class MinioTemplate implements InitializingBean {

    @Autowired
    private OssConfig ossConfig;

    private MinioClient minioClient;

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

    @Override
    public void afterPropertiesSet() {
        this.minioClient =  MinioClient.builder().endpoint(ossConfig.getEndpoint())
                .credentials(ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret())
                .build();
    }


    /**
     * 删除文件
     *
     * @param objectName 文件名称
     * @throws Exception 参考https://docs.minio.io/cn/java-client-api-reference.html#removeObject
     */
    public void removeObject(String objectName) throws Exception {
        minioClient.removeObject(RemoveObjectArgs.builder().object(objectName).bucket(ossConfig.getBucket()).build());
    }

    /**
     * 获得上传的URL
     * @param objectName 文件路径(对象名)
     */
    public String getPresignedObjectUrl(String objectName){
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(ossConfig.getBucket()).object(objectName).expiry(10, TimeUnit.MINUTES).method(Method.PUT).build());
        } catch (Exception e) {
            e.printStackTrace();
            throw new Mall4cloudException(ResponseEnum.EXCEPTION);
        }
    }

    public void uploadMinio(byte[] bytes, String filePath, String contentType) throws IOException {
        InputStream input = null;
        try {
            input = new ByteArrayInputStream(bytes);
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(ossConfig.getBucket())
                            .contentType(contentType)
                            .stream(input, input.available(), -1)
                            .object(filePath)
                            .build()
            );
        } catch (Exception e) {
            logger.error("minio上传文件错误:", e);
        } finally {
            if (Objects.nonNull(input)) {
                input.close();
            }
        }
    }
}

2.3 自动配置

在了解了BAT公司提供的对象存储OSS后,发现其API接口标准都是差不多的,从扩展性的角度出发,我们当前服务应当支持各种类型的OSS,比如阿里等。所以这里先定义一个枚举类,提供除了Minio还适配其他厂商的支持。

java 复制代码
/**
 * 文件上传存储类型
 * @author wuKeFan
 * @date 2021/01/20
 */
public enum OssType {

	/**
	 * 阿里云oss
	 */
	ALI(0),

	/**
	 * minio
	 */
	MINIO(1),
;

	private final Integer value;

	public Integer value() {
		return value;
	}

	OssType(Integer value) {
		this.value = value;
	}

}

3 测试

首先,在yml中添加Minio的配置:

yaml 复制代码
biz:
  oss:
    # resources-url是带有bucket的
    resources-url: http://127.0.0.1:9000/mall4cloud
    # 文件上传类型 0.阿里云 1.minio
    type: 1
    endpoint: http://127.0.0.1:9000
    bucket: mall4cloud
    access-key-id: username
    access-key-secret: password

然后创建一个访问接口,直接调用minioTemplate进行文件操作,这样就十分便利,达到了简化开发的目的

java 复制代码
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.mall4j.cloud.biz.config.MinioTemplate;
import com.mall4j.cloud.biz.config.OssConfig;
import com.mall4j.cloud.biz.constant.OssType;
import com.mall4j.cloud.biz.vo.OssVO;
import com.mall4j.cloud.common.response.ServerResponseEntity;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author wuKeFan
 * @date 2020/9/10
 */
@RequestMapping(value = "/oss")
@RestController
@Tag(name = "文件管理")
public class OssController {

    /**
     * 上传的文件夹(根据时间确定)
     */
    public static final String NORM_DAY_PATTERN = "yyyy/MM/dd";

    @Autowired
    private OssConfig ossConfig;
    @Autowired
    private MinioTemplate minioTemplate;


    @GetMapping(value = "/info")
    @Operation(summary = "token" , description = "获取文件上传需要的token")
    @Parameter(name = "fileNum", description = "需要获取token的文件数量")
    public ServerResponseEntity<OssVO> info(@RequestParam("fileNum") Integer fileNum) {
        OssVO ossVO = new OssVO();
        // minio文件上传
        if (Objects.equals(ossConfig.getOssType(), OssType.MINIO.value())) {
            fillMinIoInfo(ossVO, fileNum);
        }
        return ServerResponseEntity.success(ossVO);
    }

    private void fillMinIoInfo(OssVO ossVo, Integer fileNum) {
        List<OssVO> ossVOList = new ArrayList<>();
        for (int i = 0; i<fileNum; i++) {
            OssVO oss = loadOssVO(new OssVO());
            String actionUrl = minioTemplate.getPresignedObjectUrl(oss.getDir() + oss.getFileName());
            oss.setActionUrl(actionUrl);
            ossVOList.add(oss);
        }
        ossVo.setOssList(ossVOList);
    }

    private OssVO loadOssVO(OssVO ossVo) {
        String dir = DateUtil.format(new Date(), NORM_DAY_PATTERN)+ "/";
        String fileName = IdUtil.simpleUUID();
        ossVo.setDir(dir);
        ossVo.setFileName(fileName);
        return ossVo;
    }


    @PostMapping("/upload_minio")
    @Operation(summary = "文件上传接口" , description = "上传文件,返回文件路径与域名")
    public ServerResponseEntity<OssVO> uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            return ServerResponseEntity.success();
        }
        OssVO oss = loadOssVO(new OssVO());
        minioTemplate.uploadMinio(file.getBytes(), oss.getDir() + oss.getFileName(), file.getContentType());
        return ServerResponseEntity.success(oss);
    }


}
相关推荐
陌上花开࿈27 分钟前
调用第三方接口
java
Aileen_0v035 分钟前
【玩转OCR | 腾讯云智能结构化OCR在图像增强与发票识别中的应用实践】
android·java·人工智能·云计算·ocr·腾讯云·玩转腾讯云ocr
桂月二二2 小时前
Java与容器化:如何使用Docker和Kubernetes优化Java应用的部署
java·docker·kubernetes
liuxin334455663 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
小马爱打代码3 小时前
设计模式详解(建造者模式)
java·设计模式·建造者模式
栗子~~3 小时前
idea 8年使用整理
java·ide·intellij-idea
2301_801483694 小时前
Maven核心概念
java·maven
Q_19284999064 小时前
基于Spring Boot的电影售票系统
java·spring boot·后端
陈无左耳、4 小时前
Spring Boot应用开发实战:从入门到精通
spring boot
我要学编程(ಥ_ಥ)5 小时前
初始JavaEE篇 —— 网络原理---传输层协议:深入理解UDP/TCP
java·网络·tcp/ip·udp·java-ee