package com.ard.oss.service.impl;
|
|
import com.ard.common.config.OssConfiguration;
|
import com.ard.oss.model.CredentialsDTO;
|
import com.ard.oss.model.enums.OssTypeEnum;
|
import com.ard.oss.service.IOssService;
|
import io.minio.*;
|
import io.minio.credentials.AssumeRoleProvider;
|
import io.minio.errors.*;
|
import io.minio.http.Method;
|
import lombok.extern.slf4j.Slf4j;
|
import okhttp3.OkHttpClient;
|
import org.springframework.stereotype.Service;
|
|
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
import java.io.ByteArrayInputStream;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.net.URL;
|
import java.security.InvalidKeyException;
|
import java.security.NoSuchAlgorithmException;
|
import java.security.ProviderException;
|
import java.security.SecureRandom;
|
import java.security.cert.X509Certificate;
|
import java.util.Objects;
|
|
import static com.ard.common.config.OssConfiguration.*;
|
|
/**
|
* @author sean
|
* @version 0.3
|
* @date 2021/12/23
|
*/
|
@Service
|
@Slf4j
|
public class MinIOServiceImpl implements IOssService {
|
|
private MinioClient client;
|
|
@Override
|
public String getOssType() {
|
return OssTypeEnum.MINIO.getType();
|
}
|
|
|
public CredentialsDTO getCredentials111() {
|
try {
|
AssumeRoleProvider provider = new AssumeRoleProvider(endpoint, accessKey,
|
secretKey, Math.toIntExact(OssConfiguration.expire),
|
null, OssConfiguration.region, null, null, null, null);
|
return new CredentialsDTO(provider.fetch(), OssConfiguration.expire);
|
} catch (NoSuchAlgorithmException e) {
|
log.debug("Failed to obtain sts.");
|
e.printStackTrace();
|
}
|
return null;
|
}
|
@Override
|
public CredentialsDTO getCredentials() {
|
try {
|
// 创建自签证书的 OkHttpClient
|
TrustManager[] trustAllCerts = new TrustManager[]{
|
new X509TrustManager() {
|
@Override
|
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
|
@Override
|
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
|
@Override
|
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
|
}
|
};
|
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
|
sslContext.init(null, trustAllCerts, new SecureRandom());
|
OkHttpClient httpClient = new OkHttpClient.Builder()
|
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
|
.hostnameVerifier((hostname, session) -> true)
|
.build();
|
|
// 构建 AssumeRoleProvider,使用自定义 httpClient
|
AssumeRoleProvider provider = new AssumeRoleProvider(
|
endpoint,
|
accessKey,
|
secretKey,
|
Math.toIntExact(OssConfiguration.expire),
|
null,
|
OssConfiguration.region,
|
null,
|
null,
|
null,
|
httpClient
|
);
|
|
// 获取 STS 凭证
|
var stsCredentials = provider.fetch();
|
return new CredentialsDTO(stsCredentials, OssConfiguration.expire);
|
|
} catch (ProviderException e) {
|
log.error("Failed to parse STS response", e);
|
throw new RuntimeException("STS response parse failed", e);
|
} catch (NoSuchAlgorithmException | java.security.KeyManagementException e) {
|
log.error("Failed to create custom SSL context", e);
|
throw new RuntimeException("SSL setup failed", e);
|
}
|
}
|
|
@Override
|
public URL getObjectUrl(String bucket, String objectKey) {
|
try {
|
return new URL(
|
client.getPresignedObjectUrl(
|
GetPresignedObjectUrlArgs.builder()
|
.method(Method.GET)
|
.bucket(bucket)
|
.object(objectKey)
|
.expiry(Math.toIntExact(OssConfiguration.expire))
|
.build()));
|
} catch (ErrorResponseException | InsufficientDataException | InternalException |
|
InvalidKeyException | InvalidResponseException | IOException |
|
NoSuchAlgorithmException | XmlParserException | ServerException e) {
|
throw new RuntimeException("The file does not exist on the OssConfiguration.");
|
}
|
}
|
|
@Override
|
public Boolean deleteObject(String bucket, String objectKey) {
|
try {
|
client.removeObject(RemoveObjectArgs.builder()
|
.bucket(bucket)
|
.object(objectKey)
|
.build());
|
} catch (MinioException | NoSuchAlgorithmException | IOException | InvalidKeyException e) {
|
log.error("Failed to delete file.");
|
e.printStackTrace();
|
return false;
|
}
|
return true;
|
}
|
|
@Override
|
public InputStream getObject(String bucket, String objectKey) {
|
try {
|
GetObjectResponse object = client.getObject(GetObjectArgs.builder()
|
.bucket(bucket)
|
.object(objectKey)
|
.build());
|
return new ByteArrayInputStream(object.readAllBytes());
|
} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
|
e.printStackTrace();
|
}
|
return InputStream.nullInputStream();
|
}
|
|
@Override
|
public void putObject(String bucket, String objectKey, InputStream input) {
|
try {
|
client.statObject(StatObjectArgs.builder()
|
.bucket(bucket)
|
.object(objectKey)
|
.build());
|
throw new RuntimeException("The filename already exists.");
|
} catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
|
log.info("The file does not exist, start uploading.");
|
try {
|
// 设置 partSize 为 10MB
|
long partSize = 10 * 1024 * 1024;
|
ObjectWriteResponse response = client.putObject(
|
PutObjectArgs.builder()
|
.bucket(bucket)
|
.object(objectKey)
|
.stream(input, -1, partSize)
|
.build());
|
log.info("Upload File: {}", response.etag());
|
} catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException ex) {
|
log.error("Failed to upload File {}.", objectKey);
|
ex.printStackTrace();
|
}
|
}
|
}
|
|
@Override
|
public void putObject(String bucket, String objectKey, InputStream input, String contentType) {
|
try {
|
// 检查文件是否已经存在
|
client.statObject(StatObjectArgs.builder()
|
.bucket(bucket)
|
.object(objectKey)
|
.build());
|
throw new RuntimeException("The file already exists: " + objectKey);
|
} catch (ErrorResponseException e) {
|
// 如果文件不存在,则继续上传
|
log.info("The file does not exist, start uploading.");
|
try {
|
// 设置 partSize 为 10MB
|
long partSize = 10 * 1024 * 1024; // 每块 10MB
|
PutObjectArgs.Builder putArgsBuilder = PutObjectArgs.builder()
|
.bucket(bucket)
|
.object(objectKey)
|
.stream(input, -1, partSize);
|
|
// 如果提供了 Content-Type,则设置该类型
|
if (contentType != null && !contentType.isEmpty()) {
|
putArgsBuilder.contentType(contentType);
|
}
|
|
// 上传文件
|
ObjectWriteResponse response = client.putObject(putArgsBuilder.build());
|
log.info("Uploaded file successfully: {}, ETag: {}", objectKey, response.etag());
|
|
} catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException ex) {
|
log.error("Failed to upload file: {}", objectKey, ex);
|
throw new RuntimeException("File upload failed: " + objectKey, ex);
|
}
|
} catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
|
// 如果 statObject 发生错误,说明服务端错误或其他问题
|
log.error("Failed to check if file exists: {}", objectKey, e);
|
throw new RuntimeException("Failed to check if file exists: " + objectKey, e);
|
}
|
}
|
|
@Override
|
public void createClient() {
|
if (Objects.nonNull(this.client)) {
|
return;
|
}
|
try {
|
TrustManager[] trustAllCerts = new TrustManager[]{
|
new X509TrustManager() {
|
@Override
|
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
|
@Override
|
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
|
@Override
|
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
|
}
|
};
|
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
sslContext.init(null, trustAllCerts, new SecureRandom());
|
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
|
OkHttpClient httpClient = new OkHttpClient.Builder()
|
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
|
.hostnameVerifier((hostname, session) -> true)
|
.build();
|
|
this.client = MinioClient.builder()
|
.endpoint(endpoint)
|
.credentials(accessKey, secretKey)
|
.httpClient(httpClient)
|
.build();
|
} catch (Exception e) {
|
throw new RuntimeException("Failed to create unsafe MinioClient", e);
|
}
|
}
|
}
|