2.docker安装minio
2.1使用命令
docker search minio
![](https://i-blog.csdnimg.cn/blog_migrate/374d8ef91b0e530383d63225c8c0d29c.png)
2.2拉取镜像
docker pull minio/minio
![](https://i-blog.csdnimg.cn/blog_migrate/2b265b63fa082f9e75545fa336bb4254.png)
2.3 启动容器
- 这里的 \ 指的是命令是指换行
- 这里的9090端口指的是minio的客户端端口。虽然设置9090,但是我们在访问9000的时候,他也会自动跳到9090。
- 9000端口是minio的服务端端口,我们程序在连接minio的时候,就是通过这个端口来连接的。
- -v就是docker run当中的挂载,这里的/opt/data/minio/data:/data意思就是将容器的/data目录和宿主机的/opt/data/minio/data目录做映射,这样我们想要查看容器的文件的时候,就不需要看容器当中的文件了。
- 注意在执行命令的时候,他是会自动在宿主机当中创建目录的。我们不需要手动创建。
- minio所上传的文件默认都是存储在容器的data目录下的!
- 假如删除容器了宿主机当中挂载的目录是不会删除的。假如没有使用-v挂载目录,那他在宿主机的存储位置的文件会直接删除的。
- 宿主机的挂载目录一定是根目录,如果是相对路径会有问题。还有容器当中的目录也是必须是绝对路径(根路径就是带/的)。
- 所谓的挂载其实就是将容器目录和宿主机目录进行绑定了,操作宿主机目录,容器目录也会变化,操作容器目录,宿主机目录也会变化。这样做的目的 可以间接理解为就是数据持久化,防止容器误删,导致数据丢失的情况。
- MINIO_ACCESS_KEY:账号 MINIO_SECRET_KEY:密码 (正常账号应该不低于3位,密码不低于8位,不然容器会启动不成功)
- –console-address 指定客户端端口
- -d --restart=always 代表重启linux的时候容器自动启动
- –name minio 容器名称
docker run -p 9000:9000 -p 9090:9090 \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=admin" \
-e "MINIO_SECRET_KEY=admin123456" \
-v /opt/data/minio/data:/data \
-v /opt/data/minio/config:/root/.minio \
minio/minio server\
/data --console-address ":9090" -address ":9000"
2.4查看容器
docker ps
![](https://i-blog.csdnimg.cn/blog_migrate/1fefff05aecced98d464b9d4ba9beed9.png)
2.5 访问可视化界面 ip:9000
![](https://i-blog.csdnimg.cn/blog_migrate/326993c0bc6785f66a2a3aae983c8898.png)
3.springboot集成
3.1导包
<!--minio-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.0.3</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.12.0</version>
</dependency>
3.2编写配置文件
spring:
# 配置文件上传大小限制
servlet:
multipart:
max-file-size: 200MB
max-request-size: 200MB
minio:
endpoint: http://ip:9000
accessKey: admin
secretKey: admin123456
bucketName: test
server:
port: 7003
3.3编写配置类
@Data
@Configuration
public class MinioConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
/**
* 注入minio 客户端
* @return
*/
@Bean
public MinioClient minioClient(){
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
3.4编写工具类
package com.buba.config;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import lombok.SneakyThrows;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Component
public class MinioUtils {
@Autowired
private MinioClient minioClient;
/**
* 判断桶是否存在
*/
@SneakyThrows(Exception.class)
public boolean bucketExists(String bucketName) {
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
}
/**
* 创建桶
* @param bucketName
* 获取全部的桶 minioClient.listBuckets();
*/
@SneakyThrows(Exception.class)
public void createBucket(String bucketName) {
if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
/**
* 根据bucketName获取信息
* @param bucketName bucket名称
*/
@SneakyThrows(Exception.class)
public Optional<Bucket> getBucket(String bucketName) {
return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
}
/**
* 根据bucketName删除信息
* @param bucketName bucket名称
*/
@SneakyThrows(Exception.class)
public void removeBucket(String bucketName) {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
}
/**
* 获取文件流
* @param bucketName bucket名称
* @param objectName 文件名称
* @return 二进制流
*/
@SneakyThrows(Exception.class)
public InputStream getObject(String bucketName, String objectName) {
return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
/**
* 上传本地文件
* @param bucketName 存储桶
* @param objectName 对象名称
* @param fileName 本地文件路径
*/
@SneakyThrows(Exception.class)
public ObjectWriteResponse putObject(String bucketName, String objectName, String fileName) {
if(!bucketExists(bucketName)){
createBucket(bucketName);
}
return minioClient.uploadObject(UploadObjectArgs.builder().bucket(bucketName).object(objectName).filename(fileName).build());
}
/**
* 通过流上传文件
* @param bucketName 存储桶
* @param objectName 文件对象
* @param inputStream 文件流
*/
@SneakyThrows(Exception.class)
public ObjectWriteResponse putObject(String bucketName, String objectName, InputStream inputStream) {
if(!bucketExists(bucketName)){
createBucket(bucketName);
}
return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());
}
/**
* 單個文件上傳遞
* @param bucketName
* @param multipartFile
* @return
*/
// @SneakyThrows(Exception.class)
public String uploadFileSingle(String bucketName, MultipartFile multipartFile ) {
if(!bucketExists(bucketName)){
createBucket(bucketName);
}
String fileName = multipartFile.getOriginalFilename();
String[] split = fileName.split("\\.");
if (split.length > 1) {
fileName = split[0] + "_" + System.currentTimeMillis() + "." + split[1];
} else {
fileName = fileName + System.currentTimeMillis();
}
InputStream in = null;
try {
in = multipartFile.getInputStream();
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(in, in.available(), -1).contentType(multipartFile.getContentType()).build());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return getUploadObjectUrl(bucketName,fileName, 7*24*60*60);
}
/**
* description: 上传文件
* @param multipartFile
* @return: java.lang.String
*/
public List<String> uploadFileBatch(String bucketName, MultipartFile[] multipartFile) {
if(!bucketExists(bucketName)){
createBucket(bucketName);
}
List<String> names = new ArrayList<>();
for (MultipartFile file : multipartFile) {
try {
String fileName = file.getOriginalFilename();
uploadFileSingle(bucketName,file);
names.add(fileName);
}catch (Exception e){
e.printStackTrace();
}
}
return names;
}
/**
* 获取文件外链
* @param bucketName bucket名称
* @param objectName 文件名称
* @param expires 过期时间 <=7 秒级
* @return url
*/
@SneakyThrows(Exception.class)
public String getUploadObjectUrl(String bucketName, String objectName, Integer expires) {
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.PUT).bucket(bucketName).object(objectName).expiry(expires).build());
}
/**
* 下载文件
* bucketName:桶名
* @param fileName: 文件名
*/
@SneakyThrows(Exception.class)
public void download(String bucketName,String fileName, HttpServletResponse response) {
// 获取对象的元数据
StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
response.setContentType(stat.contentType());
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
InputStream is = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
IOUtils.copy(is, response.getOutputStream());
is.close();
}
}
3.5编写测试接口
@RestController
@Slf4j
public class TestController {
@Autowired
private MinioUtils minioUtils;
// @SneakyThrows
@PostMapping("/uploadFile")
@ResponseBody
public String uploadFile(@RequestParam("file") MultipartFile multipartFile){
log.info("uploadFile ---- ----- start ");
String imgPath = minioUtils.uploadFileSingle("test", multipartFile);
log.info("uploadFile ---- ----- end {}",imgPath);
return imgPath;
}
}
3.6使用postman测试接口
![](https://i-blog.csdnimg.cn/blog_migrate/b8afa28432439c6967808542f27c123f.png)
3.7查看可视化界面
![](https://i-blog.csdnimg.cn/blog_migrate/e2a84de39a4f079757fbb93077ac5f81.png)