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/
输入创建容器是的用户名和密码,进入可视化界面创建bucket,我这里创建好了
创建好的桶可以在挂载的data目录下找到相应文件夹
关于可视化界面的部分就不多介绍了,小伙伴们可自行摸索,都是一些简单的英文还附带图标
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是你自己的本地地址
上传后的文件可以在可视化界面看到
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使其生效