docker安装Minio
一、docker安装minio
1、拉取镜像
bash
docker pull minio/minio
2、启动镜像
(1)http启动
创建相关数据目录
bash
mkdir -p /wz_conf/minio/data
mkdir -p /wz_conf/minio/config
bash
docker run -d \
--name my_minio \
-p 9000:9000 \
-p 9001:9001 \
-v /wz_conf/minio/data:/data \
-v /wz_conf/minio/config:/root/.minio \
-e MINIO_ROOT_USER=admin \
-e MINIO_ROOT_PASSWORD=admin \
minio/minio server /data --console-address ":9001"
说明:
- -v /wz_conf/minio/data:/data 挂载数据目录
- -v /wz_conf/minio/config:/root/.minio 挂载配置目录
- -e MINIO_ROOT_USER=admin 配置登陆用户名
- -e MINIO_ROOT_PASSWORD=admin 配置登陆密码
- --console-address ":9001" 服务端口为9001
访问: http://ip:9001
(2)https启动
这里使用自签名证书:
bash
openssl genrsa -out /wz_conf/server.key 2048
openssl req -new -key /wz_conf/server.key -out /wz_conf/server.csr
openssl x509 -req -days 365 -in /wz_conf/server.csr -signkey /wz_conf/server.key -out /wz_conf/server.crt
启动命令如下:
bash
docker run -d \
--name my_minio \
-p 9000:9000 \
-p 9001:9001 \
-v /wz_conf/minio/data:/data \
-v /wz_conf/minio/config:/root/.minio \
-v /wz_conf/server.crt:/root/.minio/certs/public.crt \
-v /wz_conf/server.key:/root/.minio/certs/private.key \
-e MINIO_ROOT_USER=admin \
-e MINIO_ROOT_PASSWORD=admin \
-e MINIO_HTTPS_CERT_FILE=/root/.minio/certs/public.crt \
-e MINIO_HTTPS_KEY_FILE=/root/.minio/certs/private.key \
minio/minio server /data --console-address ":9001"
访问: https://ip:9001
至此,安装完成!
更多详细说明可以查阅官方说明:
minio官方文档
二、SpringBoot集成minio
1、整合前准备
创建用户:
创建组
创建accessKey和secretKey,使用代码连接是需要用到,注意保存好
创建Bucket,代码中自行创建也可以
2、代码整合
(1)导入maven做标
bash
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.2</version>
</dependency>
(2)配置application.yml
yaml
spring:
minio:
access-key: *****************************
secret-key: *****************************
url: https://ip:9000
bucket-name: ******
(3)添加配置类
注:由于这里使用的自签名证书,minio使用https连接api会出现如下错误,这里在配置胡总忽略证书验证。
java
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
配置类如下,这里兼容了http与https两个形式的连接:
java
import io.minio.MinioClient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.minio")
@Slf4j
public class MinioConfig {
private String accessKey;
private String secretKey;
private String url;
private String bucketName;
@Bean
public MinioClient minioClient() {
if(url.startsWith("https")) {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (Exception e) {
log.error("Install the all-trusting trust manager error:{}", e.getMessage());
}
OkHttpClient customHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((hostname, session) -> true)
.build();
return MinioClient.builder()
.endpoint(url)
.credentials(accessKey, secretKey)
.httpClient(customHttpClient)
.build();
} else {
return MinioClient.builder()
.endpoint(url)
.credentials(accessKey, secretKey)
.build();
}
}
}
(4)自定义工具类
java
import cn.hutool.core.io.FastByteArrayOutputStream;
import com.webuild.ai.config.MinioConfig;
import com.webuild.common.core.util.U;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class MinioUtils {
@Autowired
private MinioClient minioClient;
@Autowired
private MinioConfig minioConfig;
/**
* 判断bucket是否存在,不存在则创建
*
* @Description
* @Param bucketName bucket名称
* @Return java.lang.Boolean
* @Author Administrator
* @Date 2024/7/17 14:31
**/
public Boolean bucketExists(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
boolean exists = false;
exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!exists) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
exists = true;
}
return exists;
}
/**
* 创建存储bucket
*
* @Description
* @Param bucketName
* @Return java.lang.Boolean
* @Author Administrator
* @Date 2024/7/17 14:42
**/
public Boolean makeBucket(String bucketName, String directoryPath) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucketName)
.build());
return true;
}
/**
* 删除存储bucket
*
* @Description
* @Param bucketName
* @Return java.lang.Boolean
* @Author Administrator
* @Date 2024/7/17 14:44
**/
public Boolean removeBucket(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
minioClient.removeBucket(RemoveBucketArgs.builder()
.bucket(bucketName)
.build());
return true;
}
/**
* 获取全部bucket
*
* @Description
* @Return java.util.List<io.minio.messages.Bucket>
* @Author Administrator
* @Date 2024/7/17 14:44
**/
public List<Bucket> getAllBuckets() throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
return minioClient.listBuckets();
}
/**
* 上传文件
*
* @Description
* @Param bucketName
* @Param prefix
* @Param file
* @Return java.lang.String
* @Author Administrator
* @Date 2024/7/17 14:51
**/
public String upload(String bucketName, String prefix, MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
String originalFilename = file.getOriginalFilename();
if (StringUtils.isBlank(originalFilename)) {
throw new RuntimeException();
}
boolean fileExists;
try {
fileExists = isFileExists(bucketName, prefix, originalFilename);
} catch (Exception e) {
fileExists = false;
}
if(fileExists) {
log.info("当前文件存在同名文件,开始重命名保存. originalFilename={}", originalFilename);
int dotIndex = originalFilename.lastIndexOf('.');
// 获取不带后缀名的文件名
String fileNameWithoutExtension = originalFilename.substring(0, dotIndex);
// 获取文件后缀名
String fileExtension = originalFilename.substring(dotIndex + 1);
originalFilename = fileNameWithoutExtension + "_" + System.currentTimeMillis() + "." + fileExtension;
}
String objectName = U.isBlank(prefix) ? originalFilename : "/" + prefix + "/" + originalFilename;
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName)
.stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
//文件名称相同会覆盖
minioClient.putObject(objectArgs);
return originalFilename;
}
/**
* 上传报警图片
*
* @Description
* @Param bucketName
* @Param prefix
* @Param suffix
* @Param fileBytes
* @Return java.lang.String
* @Author Administrator
* @Date 2024/7/23 16:38
**/
public String upload(String bucketName, String prefix, String suffix, byte[] fileBytes) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
String originalFilename = UuidUtil.getUuid() + suffix;
String objectName = U.isBlank(prefix) ? originalFilename : "/" + prefix + "/" + originalFilename;
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName)
.stream(inputStream, fileBytes.length, -1).build();
//文件名称相同会覆盖
minioClient.putObject(objectArgs);
return originalFilename;
}
/**
* 预览(预览链接默认7天后过期)
*
* @Description
* @Param bucketName
* @Param fileName
* @Return java.lang.String
* @Author Administrator
* @Date 2024/7/17 14:54
**/
public String preview(String bucketName, String prefix, String fileName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
// 查看文件地址
String objectName = U.isBlank(prefix) ? fileName : "/" + prefix + "/" + fileName;
GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).method(Method.GET).build();
return minioClient.getPresignedObjectUrl(build);
}
/**
* 下载文件
*
* @Description
* @Param bucketName
* @Param fileName
* @Param res
* @Return void
* @Author Administrator
* @Date 2024/7/17 14:56
**/
public void download(String bucketName, String prefix, String fileName, HttpServletResponse res) {
String objectName = U.isBlank(prefix) ? fileName : "/" + prefix + "/" + fileName;
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(objectName).build();
try (GetObjectResponse response = minioClient.getObject(objectArgs)) {
byte[] buf = new byte[1024];
int len;
try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
while ((len = response.read(buf)) != -1) {
os.write(buf, 0, len);
}
os.flush();
byte[] bytes = os.toByteArray();
res.setCharacterEncoding("utf-8");
// 设置强制下载不打开
// res.setContentType("application/force-download");
res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
try (ServletOutputStream stream = res.getOutputStream()) {
stream.write(bytes);
stream.flush();
}
}
} catch (Exception e) {
log.error("下载文件异常. e={}", e);
}
}
/**
* 查看文件对象
*
* @Description
* @Param bucketName
* @Return java.util.List<io.minio.messages.Item>
* @Author Administrator
* @Date 2024/7/17 15:32
**/
public List<Item> listObjects(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).build());
List<Item> items = new ArrayList<>();
for (Result<Item> result : results) {
items.add(result.get());
}
return items;
}
/**
* 删除文件
*
* @Description
* @Param bucketName
* @Param fileName
* @Return boolean
* @Author Administrator
* @Date 2024/7/17 15:32
**/
public boolean remove(String bucketName, String prefix, String fileName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
String objectName = U.isBlank(prefix) ? fileName : "/" + prefix + "/" + fileName;
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
return true;
}
/**
* 生成一个带到期时间、签名的URL,这个地址可以提供给没有登录的第三方共享访问或者上传对象,针对于Bucket为私有的情况
*
* @Description
* @Param bucketName
* @Param fileName
* @Return java.lang.String
* @Author Administrator
* @Date 2024/7/17 16:22
**/
public String getPresignedObjectUrl(String bucketName, String prefix, String fileName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
String objectName = U.isBlank(prefix) ? fileName : "/" + prefix + "/" + fileName;
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(objectName)
// 设置过期时间,30分钟
.expiry(30, TimeUnit.MINUTES)
.method(Method.GET)
.build());
}
/**
* 判断文件是否存在
*
* @Description
* @Param bucketName
* @Param prefix
* @Param fileName
* @Return boolean
* @Author Administrator
* @Date 2024/7/22 17:42
**/
public boolean isFileExists(String bucketName, String prefix, String fileName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
String objectName = U.isBlank(prefix) ? fileName : "/" + prefix + "/" + fileName;
minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
return true;
}
}
到此就可以通过自己的工具类使用minio了...