1、简介

开发项目时需要用到对象存储功能,而minio是github上一款开源的提供对象存储服务的项目,使用go语言开发,如果不想花钱购买主流大厂的对象存储服务(虽然不贵),可以参考本文的配置,在docker部署minio并将其集成到springboot项目中

2、docker部署minio

        关于minio的部署与使用可参照官方文档:MinIO | The MinIO Quickstart Guide,虽然minio有中文文档,但是很多都不准确,建议直接啃英文文档,也可参照博主的操作

1、首先是拉取镜像,参照官方文档示例,可以看到镜像名为:quay.io/minio/minio

docker run \ -p 9000:9000 \ -p 9001:9001 \ -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \ -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \ quay.io/minio/minio server /data --console-address ":9001"

 执行拉取命令:

docker pull quay.io/minio/minio

2、拉取镜像后就是创建容器了,接着查看官方文档

docker run \
  -p 9000:9000 \
  -p 9001:9001 \
  --name minio1 \
  -v ~/minio/data:/data \
  -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \
  -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
  quay.io/minio/minio server /data --console-address ":9001"

【1】留意到有两个端口,功能分别是:

        9000:服务实际映射端口,上传文件时使用这个端口 

        9001:minio提供了一个可视化界面,该可视化界面映射到了9001

【2】 -e设置的分别是用户名和密码

        可使用该用户名和密码登陆可视化界面;

        进行文件上时也会用到用户名和密码;

【3】-v 是进行目录挂载,以冒号区分前后

        前者是宿主机路径,后者是容器路径

        该命令将容器的/data目录挂载到宿主机的~/minio/data下,容器的/data用于存放minio

        中的 bucket,bucket是一个文件夹,用于存放上传的文件,上传文件时指定bucket的名称,

        就可以将文件上传到相应的bucket中了;进行挂载后,容器/data中的bucket和上传的

        对象就都可以在宿主机~/minio/data目录访问了

3、创建完容器后启动容器并访问客户端可视化界面

        启动容器:docker start minio1

        访问客户端:http://[ip地址]:9001/

        

docker中使用swoole udp docker中使用pinia_docker中使用swoole udp

 输入创建容器是的用户名和密码,进入可视化界面创建bucket,我这里创建好了

        

docker中使用swoole udp docker中使用pinia_docker_02

         

docker中使用swoole udp docker中使用pinia_容器_03

         创建好的桶可以在挂载的data目录下找到相应文件夹

        

docker中使用swoole udp docker中使用pinia_容器_04

        关于可视化界面的部分就不多介绍了,小伙伴们可自行摸索,都是一些简单的英文还附带图标 

4、java代码上传文件

1、同样参照官方文档,首先引入依赖

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

2、demo代码如下:

@Test
    public void test() {
        //1、获取客户端
        MinioClient minioClient =
                MinioClient.builder()
                        //服务所在地址
                        .endpoint("http://localhost:9000")
                        //用户名和密码
                        .credentials("admin", "admin")
                        .build();
        //初始化判断参数
        boolean found = false;
        try {
            //判断bucket是否存在,不存在则创建
            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket("test").build());
            if(!found) {
                //创建桶的代码
                minioClient.makeBucket(MakeBucketArgs.builder().bucket("test").build());
            }
            minioClient.uploadObject(
                    //上传代码
                    UploadObjectArgs.builder()
                            //bucket名
                            .bucket("test")
                            //上传后的文件名
                            .object("任务(1).docx")
                            //这里要上传的文件本地地址,注意是文件本地地址
                            .filename("C:\\Users\\Administrator\\Desktop\\任务(1).docx")
                            .build());
            System.out.println("文件上传成功");
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }

    }

唯一需要注意的点就是别把参数传错了,filename是你自己的本地地址

上传后的文件可以在可视化界面看到

docker中使用swoole udp docker中使用pinia_容器_05

 3、springboot集成minio

        (1)第一种实现

        这里提供一种思路,既然使用springboot,那么就将所需的minioClient对象交给spring容器管理,步骤如下

        1、首先引入依赖

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

        2、创建一个配置类,使得所需参数可以写入application配置文件中

            对于服务地址、用户名和密码这三个参数,类似于mysql中的数据源,我们可以考虑在application.yml配置文件中管理他们。

           可以将他们声明一个配置类,spring容器启动后从application.yml中读取这三个参数并封装成该配置类的一个对象,后续操作就可以通过注入该对象的方式来获取参数了

@Component
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
    private String endpoint;
    private String accessKey;
    private String secretKey;

    public String getEndpoint() {
        return endpoint;
    }

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

    public String getAccessKey() {
        return accessKey;
    }

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

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }
}
minio: 
  endpoint: http://localhost:9000
  accessKey: admin
  secretKey: admin

        3、将minioClient对象交给spring容器管理

                第2步我们将所需参数封装进对象中,接下来就是从容器中取出该对象获取这三个参数创建minioClient对象   

@Configuration
public class MinioConfig {
    //注入封装了参数的对象
    @Autowired
    MinioProperties minioProperties;

    //创建minioClient对象并交给spring容器
    @Bean
    public MinioClient minioClient() {
        MinioClient minioClient =
                MinioClient.builder()
                        .endpoint(minioProperties.getEndpoint())
                        .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                        .build();
        return minioClient;
    }
}

        4、接下来就可以进行测试,上传文件我们需要三个参数,分别是:

        【1】本地文件所在路径

        【2】要上传的桶

        【3】上传后的文件名称

        故创建一个实体类来接收它们

//使用lombok插件,没有使用该插件要生成set和get方法
@Data
public class PostEntity {
    String bucket;
    String filename;
    String object;
}

        接着在控制层注入minioClient对象,并开放接口用于传输文件

@RestController
@RequestMapping("thirdparty/minio")
public class MinioController {
    //注入client对象
    @Autowired
    MinioClient minioClient;
    //R是人人开源封装的返回类,可忽略
    @RequestMapping("/upload")
    public R upLoad(@RequestBody PostEntity postEntity) {
        try {
            minioClient.uploadObject(
                    UploadObjectArgs.builder()
                            .bucket(postEntity.getBucket())
                            .object(postEntity.getObject())
                            .filename(postEntity.getFilename())
                            .build());
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }
        return R.ok();
    }
  

}

(2)第二种实现

        对于服务地址、用户名、密码这三个参数如果想要实现实时更新,可以与spring cloud的nacos配置中心搭配使用

        1、引入相关依赖

<!-- 配置中心-nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>


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

        2、打开nacos可视化界面,创建配置文件minio.yml,声明三个参数

minio.endpoint: http://127.0.0.1:9000
minio.accessKey: admin
minio.secretKey: admin08nian

        3、在项目的resource文件夹下创建bootstrap.properties,加入以下配置:

# 应用名
spring.application.name=demo
# 端口号
server.port=8086
# nacos地址
spring.cloud.nacos.server-addr=localhost:8848
# nacos命名空间
spring.cloud.nacos.config.namespace=1218c19d-16e9-4589-bbd7-4aa7f97ece18
# minio对象管理
spring.cloud.nacos.config.extension-configs[0].data-id=minio.yml
# 分组
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
# 开启实时刷新
spring.cloud.nacos.config.extension-configs[0].refresh=true

        4、controller加入注解@RefreshScope

        

@RestController
@RefreshScope
@RequestMapping("thirdparty/minio")
public class MinioController {
    @Value("${minio.endpoint}")
    String endpoint;
    @Value("${minio.accessKey}")
    String accessKey;
    @Value("${minio.secretKey}")
    String secretKey;
    @RequestMapping("/upload")
    public R upLoad(@RequestBody PostEntity postEntity) {
        MinioClient minioClient =
                MinioClient.builder()
                        //服务所在地址
                        .endpoint(endpoint)
                        //用户名和密码
                        .credentials(accessKey, secretKey)
                        .build();
        try {
            minioClient.uploadObject(
                    //上传代码
                    UploadObjectArgs.builder()
                            //bucket名
                            .bucket(postEntity.getBucket())
                            //上传后的文件名
                            .object(postEntity.getObject())
                            //这里要上传的文件本地地址,注意是文件本地地址
                            .filename(postEntity.getFilename())
                            .build());
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }
        return R.ok();
    }


}

4、依赖冲突bug解决

        启动容器测试接口时出现了以下报错

        

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    io.minio.S3Base.<clinit>(S3Base.java:98)

The following method did not exist:

    okhttp3.RequestBody.create([BLokhttp3/MediaType;)Lokhttp3/RequestBody;

The method's class, okhttp3.RequestBody, is available from the following locations:

    jar:file:/D:/tool/maven/maven-repository/com/squareup/okhttp3/okhttp/3.14.4/okhttp-3.14.4.jar!/okhttp3/RequestBody.class

The class hierarchy was loaded from the following locations:

    okhttp3.RequestBody: file:/D:/tool/maven/maven-repository/com/squareup/okhttp3/okhttp/3.14.4/okhttp-3.14.4.jar

Action:

Correct the classpath of your application so that it contains a single, compatible version of okhttp3.RequestBody
 

这是由于okhttp3依赖冲突所致,springboot所使用的okhttp3低于minio所需版本,可通过以下方法解决:

1、降低minio依赖


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


2、引入高版本的okhttp依赖


<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.8.1</version>
</dependency>


最后要记得刷新maven使其生效