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


    1 前言

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

    2 Spring Boot集成Minio

    2.1 环境搭建

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

        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            
            <dependency>
                <groupId>io.miniogroupId>
                <artifactId>minioartifactId>
                <version>8.3.1version>
            dependency>
            <dependency>
                <groupId>me.tongfeigroupId>
                <artifactId>progressbarartifactId>
                <version>0.9.2version>
            dependency>
            <dependency>
                <groupId>com.squareup.okhttp3groupId>
                <artifactId>okhttpartifactId>
                <version>4.9.2version>
            dependency>
            <dependency>
                <groupId>cn.hutoolgroupId>
                <artifactId>hutool-allartifactId>
                <version>5.7.13version>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-configuration-processorartifactId>
            dependency>
            
            <dependency>
                <groupId>commons-fileuploadgroupId>
                <artifactId>commons-fileuploadartifactId>
                <version>1.4version>
            dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    2.2 操作模板类

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

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

    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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    import com.wkf.workrecord.tools.minio.config.OssConfig;
    import io.minio.GetPresignedObjectUrlArgs;
    import io.minio.MinioClient;
    import io.minio.PutObjectArgs;
    import io.minio.RemoveObjectArgs;
    import io.minio.errors.*;
    import io.minio.http.Method;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.stereotype.Component;
    import javax.annotation.Resource;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.util.Objects;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author wuKeFan
     * @date 2023-09-21 10:59:24
     */
    @Slf4j
    @Component
    public class MinioTemplate implements InitializingBean {
    
        @Resource
        private OssConfig ossConfig;
    
        private MinioClient minioClient;
    
        @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) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(ossConfig.getBucket()).object(objectName).expiry(10, TimeUnit.MINUTES).method(Method.PUT).build());
        }
    
        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) {
                log.error("minio上传文件错误:", e);
            } finally {
                if (Objects.nonNull(input)) {
                    input.close();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    2.3 自动配置

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

    /**
     * 文件上传存储类型
     * @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;
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3 测试

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

    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);
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
  • 相关阅读:
    如何确定 <board_name>名字
    Python爬虫之简单学习BeautifulSoup库,学习获取的对象常用方法,实战豆瓣Top250
    Android 发布Library 到远程maven 私服仓库(Nexus)
    websocket在java中的使用教程
    Java版本spring cloud + spring boot企业电子招投标系统源代码
    doris通关之概念、架构篇
    PyTorch的数据处理
    MyBatis注解开发
    Ubuntu20.04同时安装ROS1和ROS2
    构建镜像开源工具 buildah
  • 原文地址:https://blog.csdn.net/qq_37284798/article/details/133084693