Spring Boot整合Minio实现文件上传和读取

07-16 986阅读

文章目录

  • 一、简介
    • 1.分布式文件系统应用场景
    • 2.Minio介绍
    • 3.Minio优点
    • 二、docker部署(windows系统)
      • 1.创建目录
      • 2.拉取镜像
      • 3.创建容器并运行
      • 4.访问控制台
      • 5.初始化配置
      • 三、Spring Boot整合Minio
        • 1.创建demo项目
        • 2.引入依赖
        • 3.配置
        • 4.编写配置类
        • 5.MinIO工具类
        • 6.文件上传

          最近公司有一个需求是关于视频上传播放的,需要设计一个方案,中间谈到了Minio这个技术,于是来学习一下

          一、简介

          1.分布式文件系统应用场景

          互联网海量非结构化数据的存储需求

          • 电商网络:海量商品图片
          • 视频网站:海量视频文件
          • 网盘:海量文件
          • 社交网站:海量图片

            2.Minio介绍

            • Go语言开发,开源,免费的对象存储服务,可以存储海量非结构化的数据,一个对象文件可以是任意大小,从几kb到最大5T不等

              3.Minio优点

              • 部署简单
              • 读写性能优异
              • 支持海量存储

                二、docker部署(windows系统)

                这里我是用自己电脑(windows系统)安装了docker,然后使用docker来部署的

                中文官网:单节点多硬盘部署MinIO — MinIO中文文档 | MinIO Container中文文档

                1.创建目录

                • 先进入D盘,创建docker的工作目录 docker_workplace,再创建minio的目录minio,再创建两个文件夹data和config,如图所示

                  Spring Boot整合Minio实现文件上传和读取

                  拉取镜像,创建容器并运行

                  2.拉取镜像

                  直接cmd,敲docker命令即可,和linux的语法一样

                  Spring Boot整合Minio实现文件上传和读取

                  3.创建容器并运行

                  多行:

                  docker run -d --name minio \
                  --privileged=true \
                  --restart=always \
                  -p 9000:9000 -p 50000:50000 \
                  -e "MINIO_ROOT_USER=minio" \
                  -e "MINIO_ROOT_PASSWORD=miniominio" \
                  -v D:/docker_workplace/data/minio/config:/root/.minio \
                  -v D:/docker_workplace/data/minio/data1:/data1 \
                  -v D:/docker_workplace/data/minio/data2:/data2 \
                  -v D:/docker_workplace/data/minio/data3:/data3 \
                  -v D:/docker_workplace/data/minio/data4:/data4 \
                  minio/minio \
                  server \
                  --console-address ":50000" /data{1...4}
                  

                  单行:

                  docker run -p 9000:9000 -p 50000:50000 -d --name minio -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=miniominio" -v D:/docker_workplace/data/minio/config:/root/.minio -v D:/docker_workplace/data/minio/data1:/data1 -v D:/docker_workplace/data/minio/data2:/data2 -v D:/docker_workplace/data/minio/data3:/data3 -v D:/docker_workplace/data/minio/data4:/data4 --restart always minio/minio server --console-address ":50000" /data{1...4}
                  

                  4.访问控制台

                  浏览器访问:

                  http://localhost:50000/login

                  账号/密码(刚刚docker运行命令设置的):minio/miniominio

                  这里我第一次访问失败了,看了下docker日志,发现是账号密码长度不符合规范导致(一开始密码是minio,达不到8个字符)

                  Spring Boot整合Minio实现文件上传和读取

                  于是改了密码为miniominio,成功运行

                  Spring Boot整合Minio实现文件上传和读取

                  5.初始化配置

                  • 创建一个桶 Bucket

                    Spring Boot整合Minio实现文件上传和读取

                    这里出现了一个报错,原因是说需要分布式部署才能使用,解决办法:挂载多个卷

                    Spring Boot整合Minio实现文件上传和读取

                    Spring Boot整合Minio实现文件上传和读取

                  • 配置桶权限为public

                    Spring Boot整合Minio实现文件上传和读取

                    到这里,minio单机版就部署好了

                    三、Spring Boot整合Minio

                    1.创建demo项目

                    新建一个spring boot项目

                    2.引入依赖

                        io.minio
                        minio
                        8.3.7
                    
                    

                    3.配置

                    application.yml

                    spring:
                      application:
                        name: miniodemo
                      servlet:
                        multipart:
                          # 文件上传大小限制。超过该值直接报错
                          max-file-size: 20MB
                          # 文件最大请求限制,用于批量上传
                          max-request-size: 20MB
                      datasource:
                        url: jdbc:mysql://localhost:3306/minio?useSSL=false&serverTimezone=UTC
                        username: root
                        password: root
                        driver-class-name: com.mysql.cj.jdbc.Driver
                    # MinIO 配置
                    minio:
                      endpoint: http://localhost:9000      # MinIO服务地址
                      fileHost: http://localhost:9000      # 文件地址host
                      bucketName: test                      # 存储桶bucket名称
                      accessKey: minio                         # 用户名
                      secretKey: miniominio                     # 密码
                      imgSize: 20                           # 图片大小限制,单位:m
                      fileSize: 20                          # 文件大小限制,单位:m
                    mybatis:
                      mapper-locations: classpath:mapper/*.xml
                      type-aliases-package: com.xuyue.miniodemo.domain
                    

                    4.编写配置类

                    MinIOConfig.java

                    package com.xuyue.miniodemo.config;
                    import lombok.Data;
                    import org.springframework.beans.factory.annotation.Value;
                    import org.springframework.context.annotation.Configuration;
                    @Configuration
                    @Data
                    public class MinIOConfig {
                        @Value("${minio.endpoint}")
                        private String endpoint;
                        @Value("${minio.fileHost}")
                        private String fileHost;
                        @Value("${minio.bucketName}")
                        private String bucketName;
                        @Value("${minio.accessKey}")
                        private String accessKey;
                        @Value("${minio.secretKey}")
                        private String secretKey;
                        @Value("${minio.imgSize}")
                        private Integer imgSize;
                        @Value("${minio.fileSize}")
                        private Integer fileSize;
                    }
                    

                    5.MinIO工具类

                    MinIoUploadService.java

                    package com.xuyue.miniodemo.service;
                    import com.xuyue.miniodemo.config.MinIOConfig;
                    import io.minio.*;
                    import io.minio.http.Method;
                    import io.minio.messages.Bucket;
                    import io.minio.messages.DeleteObject;
                    import io.minio.messages.Item;
                    import lombok.extern.slf4j.Slf4j;
                    import org.springframework.stereotype.Service;
                    import org.springframework.web.multipart.MultipartFile;
                    import javax.annotation.PostConstruct;
                    import javax.annotation.Resource;
                    import java.io.ByteArrayInputStream;
                    import java.io.InputStream;
                    import java.io.UnsupportedEncodingException;
                    import java.net.URLDecoder;
                    import java.util.ArrayList;
                    import java.util.LinkedList;
                    import java.util.List;
                    import java.util.Optional;
                    /**
                     * MinIO工具类
                     */
                    @Slf4j
                    @Service
                    public class MinIoUploadService {
                        @Resource
                        private MinIOConfig minIOConfig;
                        private MinioClient minioClient;
                        private String endpoint;
                        private String bucketName;
                        private String accessKey;
                        private String secretKey;
                        private Integer imgSize;
                        private Integer fileSize;
                        private final String SEPARATOR = "/";
                        @PostConstruct
                        public void init() {
                            this.endpoint = minIOConfig.getEndpoint();
                            this.bucketName = minIOConfig.getBucketName();
                            this.accessKey = minIOConfig.getAccessKey();
                            this.secretKey = minIOConfig.getSecretKey();
                            this.imgSize = minIOConfig.getImgSize();
                            this.fileSize = minIOConfig.getFileSize();
                            createMinioClient();
                        }
                        /**
                         * 创建基于Java端的MinioClient
                         */
                        public void createMinioClient() {
                            try {
                                if (null == minioClient) {
                                    log.info("开始创建 MinioClient...");
                                    minioClient = MinioClient
                                            .builder()
                                            .endpoint(endpoint)
                                            .credentials(accessKey, secretKey)
                                            .build();
                                    createBucket(bucketName);
                                    log.info("创建完毕 MinioClient...");
                                }
                            } catch (Exception e) {
                                log.error("MinIO服务器异常:{}", e);
                            }
                        }
                        /**
                         * 获取上传文件前缀路径
                         *
                         * @return
                         */
                        public String getBasisUrl() {
                            return endpoint + SEPARATOR + bucketName + SEPARATOR;
                        }
                        /******************************  Operate Bucket Start  ******************************/
                        /**
                         * 启动SpringBoot容器的时候初始化Bucket
                         * 如果没有Bucket则创建
                         *
                         * @throws Exception
                         */
                        private void createBucket(String bucketName) throws Exception {
                            if (!bucketExists(bucketName)) {
                                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                            }
                        }
                        /**
                         * 判断Bucket是否存在,true:存在,false:不存在
                         *
                         * @return
                         * @throws Exception
                         */
                        public boolean bucketExists(String bucketName) throws Exception {
                            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
                        }
                        /**
                         * 获得Bucket的策略
                         *
                         * @param bucketName
                         * @return
                         * @throws Exception
                         */
                        public String getBucketPolicy(String bucketName) throws Exception {
                            String bucketPolicy = minioClient
                                    .getBucketPolicy(
                                            GetBucketPolicyArgs
                                                    .builder()
                                                    .bucket(bucketName)
                                                    .build()
                                    );
                            return bucketPolicy;
                        }
                        /**
                         * 获得所有Bucket列表
                         *
                         * @return
                         * @throws Exception
                         */
                        public List getAllBuckets() throws Exception {
                            return minioClient.listBuckets();
                        }
                        /**
                         * 根据bucketName获取其相关信息
                         *
                         * @param bucketName
                         * @return
                         * @throws Exception
                         */
                        public Optional getBucket(String bucketName) throws Exception {
                            return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
                        }
                        /**
                         * 根据bucketName删除Bucket,true:删除成功; false:删除失败,文件或已不存在
                         *
                         * @param bucketName
                         * @throws Exception
                         */
                        public void removeBucket(String bucketName) throws Exception {
                            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
                        }
                        /******************************  Operate Bucket End  ******************************/
                        /******************************  Operate Files Start  ******************************/
                        /**
                         * 判断文件是否存在
                         *
                         * @param bucketName 存储桶
                         * @param objectName 文件名
                         * @return
                         */
                        public boolean isObjectExist(String bucketName, String objectName) {
                            boolean exist = true;
                            try {
                                minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
                            } catch (Exception e) {
                                exist = false;
                            }
                            return exist;
                        }
                        /**
                         * 判断文件夹是否存在
                         *
                         * @param bucketName 存储桶
                         * @param objectName 文件夹名称
                         * @return
                         */
                        public boolean isFolderExist(String bucketName, String objectName) {
                            boolean exist = false;
                            try {
                                Iterable results = minioClient.listObjects(
                                        ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
                                for (Result result : results) {
                                    Item item = result.get();
                                    if (item.isDir() && objectName.equals(item.objectName())) {
                                        exist = true;
                                    }
                                }
                            } catch (Exception e) {
                                exist = false;
                            }
                            return exist;
                        }
                        /**
                         * 根据文件前缀查询文件
                         *
                         * @param bucketName 存储桶
                         * @param prefix     前缀
                         * @param recursive  是否使用递归查询
                         * @return MinioItem 列表
                         * @throws Exception
                         */
                        public List getAllObjectsByPrefix(String bucketName,
                                                                String prefix,
                                                                boolean recursive) throws Exception {
                            List list = new ArrayList();
                            Iterable objectsIterator = minioClient.listObjects(
                                    ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
                            if (objectsIterator != null) {
                                for (Result o : objectsIterator) {
                                    Item item = o.get();
                                    list.add(item);
                                }
                            }
                            return list;
                        }
                        /**
                         * 获取文件流
                         *
                         * @param bucketName 存储桶
                         * @param objectName 文件名
                         * @return 二进制流
                         */
                        public InputStream getObject(String bucketName, String objectName) throws Exception {
                            return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
                        }
                        /**
                         * 断点下载
                         *
                         * @param bucketName 存储桶
                         * @param objectName 文件名称
                         * @param offset     起始字节的位置
                         * @param length     要读取的长度
                         * @return 二进制流
                         */
                        public InputStream getObject(String bucketName, String objectName, long offset, long length) throws Exception {
                            return minioClient.getObject(
                                    GetObjectArgs.builder()
                                            .bucket(bucketName)
                                            .object(objectName)
                                            .offset(offset)
                                            .length(length)
                                            .build());
                        }
                        /**
                         * 获取路径下文件列表
                         *
                         * @param bucketName 存储桶
                         * @param prefix     文件名称
                         * @param recursive  是否递归查找,false:模拟文件夹结构查找
                         * @return 二进制流
                         */
                        public Iterable listObjects(String bucketName, String prefix,
                                                                  boolean recursive) {
                            return minioClient.listObjects(
                                    ListObjectsArgs.builder()
                                            .bucket(bucketName)
                                            .prefix(prefix)
                                            .recursive(recursive)
                                            .build());
                        }
                        /**
                         * 使用MultipartFile进行文件上传
                         *
                         * @param bucketName  存储桶
                         * @param file        文件名
                         * @param objectName  对象名
                         * @param contentType 类型
                         * @return
                         * @throws Exception
                         */
                        public ObjectWriteResponse uploadFile(String bucketName, MultipartFile file,
                                                              String objectName, String contentType) throws Exception {
                            InputStream inputStream = file.getInputStream();
                            return minioClient.putObject(
                                    PutObjectArgs.builder()
                                            .bucket(bucketName)
                                            .object(objectName)
                                            .contentType(contentType)
                                            .stream(inputStream, inputStream.available(), -1)
                                            .build());
                        }
                        /**
                         * 上传本地文件
                         *
                         * @param bucketName 存储桶
                         * @param objectName 对象名称
                         * @param fileName   本地文件路径
                         */
                        public ObjectWriteResponse uploadFile(String bucketName, String objectName,
                                                              String fileName) throws Exception {
                            return minioClient.uploadObject(
                                    UploadObjectArgs.builder()
                                            .bucket(bucketName)
                                            .object(objectName)
                                            .filename(fileName)
                                            .build());
                        }
                        /**
                         * 通过流上传文件
                         *
                         * @param bucketName  存储桶
                         * @param objectName  文件对象
                         * @param inputStream 文件流
                         */
                        public ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) throws Exception {
                            return minioClient.putObject(
                                    PutObjectArgs.builder()
                                            .bucket(bucketName)
                                            .object(objectName)
                                            .stream(inputStream, inputStream.available(), -1)
                                            .build());
                        }
                        /**
                         * 创建文件夹或目录
                         *
                         * @param bucketName 存储桶
                         * @param objectName 目录路径
                         */
                        public ObjectWriteResponse createDir(String bucketName, String objectName) throws Exception {
                            return minioClient.putObject(
                                    PutObjectArgs.builder()
                                            .bucket(bucketName)
                                            .object(objectName)
                                            .stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
                                            .build());
                        }
                        /**
                         * 获取文件信息, 如果抛出异常则说明文件不存在
                         *
                         * @param bucketName 存储桶
                         * @param objectName 文件名称
                         */
                        public String getFileStatusInfo(String bucketName, String objectName) throws Exception {
                            return minioClient.statObject(
                                    StatObjectArgs.builder()
                                            .bucket(bucketName)
                                            .object(objectName)
                                            .build()).toString();
                        }
                        /**
                         * 拷贝文件
                         *
                         * @param bucketName    存储桶
                         * @param objectName    文件名
                         * @param srcBucketName 目标存储桶
                         * @param srcObjectName 目标文件名
                         */
                        public ObjectWriteResponse copyFile(String bucketName, String objectName,
                                                            String srcBucketName, String srcObjectName) throws Exception {
                            return minioClient.copyObject(
                                    CopyObjectArgs.builder()
                                            .source(CopySource.builder().bucket(bucketName).object(objectName).build())
                                            .bucket(srcBucketName)
                                            .object(srcObjectName)
                                            .build());
                        }
                        /**
                         * 删除文件
                         *
                         * @param bucketName 存储桶
                         * @param objectName 文件名称
                         */
                        public void removeFile(String bucketName, String objectName) throws Exception {
                            minioClient.removeObject(
                                    RemoveObjectArgs.builder()
                                            .bucket(bucketName)
                                            .object(objectName)
                                            .build());
                        }
                        /**
                         * 批量删除文件
                         *
                         * @param bucketName 存储桶
                         * @param keys       需要删除的文件列表
                         * @return
                         */
                        public void removeFiles(String bucketName, List keys) {
                            List objects = new LinkedList();
                            keys.forEach(s -> {
                                objects.add(new DeleteObject(s));
                                try {
                                    removeFile(bucketName, s);
                                } catch (Exception e) {
                                    log.error("批量删除失败!error:{}", e);
                                }
                            });
                        }
                        /**
                         * 获取文件外链
                         *
                         * @param bucketName 存储桶
                         * @param objectName 文件名
                         * @param expires    过期时间 
                            GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
                            return minioClient.getPresignedObjectUrl(args);
                        }
                        /**
                         * 获得文件外链
                         *
                         * @param bucketName
                         * @param objectName
                         * @return url
                         * @throws Exception
                         */
                        public String getPresignedObjectUrl(String bucketName, String objectName) throws Exception {
                            GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                                    .bucket(bucketName)
                                    .object(objectName)
                                    .method(Method.GET).build();
                            return minioClient.getPresignedObjectUrl(args);
                        }
                        /**
                         * 将URLDecoder编码转成UTF8
                         *
                         * @param str
                         * @return
                         * @throws UnsupportedEncodingException
                         */
                        public String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
                            String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
                            return URLDecoder.decode(url, "UTF-8");
                        }
                        /******************************  Operate Files End  ******************************/
                    }
                    
                        @Autowired
                        private MinIoUploadService minIoUploadService;
                        @Autowired
                        private MinIOConfig minIOConfig;
                        /**
                         * 上传文件,返回url
                         * @param file
                         * @return
                         * @throws Exception
                         */
                        @PostMapping("upload")
                        public String upload(MultipartFile file) throws Exception {
                            String fileName = file.getOriginalFilename();
                            minIoUploadService.uploadFile(minIOConfig.getBucketName(), fileName, file.getInputStream());
                            String imgUrl = minIOConfig.getFileHost()
                                    + "/"
                                    + minIOConfig.getBucketName()
                                    + "/"
                                    + fileName;
                            return imgUrl;
                        }
                    }
                    
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]