docs 补充项目注释
This commit is contained in:
+504
-3
@@ -17,7 +17,10 @@ import software.amazon.awssdk.core.async.AsyncRequestBody;
|
||||
import software.amazon.awssdk.core.async.AsyncResponseTransformer;
|
||||
import software.amazon.awssdk.core.async.ResponsePublisher;
|
||||
import software.amazon.awssdk.services.s3.S3AsyncClient;
|
||||
import software.amazon.awssdk.services.s3.model.*;
|
||||
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
|
||||
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
|
||||
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
|
||||
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
|
||||
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
|
||||
import software.amazon.awssdk.transfer.s3.S3TransferManager;
|
||||
import software.amazon.awssdk.transfer.s3.model.CompletedUpload;
|
||||
@@ -38,8 +41,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
@@ -90,7 +93,7 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
* 构造 S3 存储客户端基础实现。
|
||||
*
|
||||
* @param clientId 客户端 ID
|
||||
* @param config S3 存储客户端配置
|
||||
* @param config S3 存储客户端配置
|
||||
*/
|
||||
public AbstractOssClientImpl(String clientId, OssClientConfig config) {
|
||||
Assert.notNull(config, () -> S3StorageException.form("S3StorageClientConfig must not be null"));
|
||||
@@ -100,22 +103,40 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端 ID。
|
||||
*
|
||||
* @return 客户端 ID
|
||||
*/
|
||||
@Override
|
||||
public String clientId() {
|
||||
return this.clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端配置副本。
|
||||
*
|
||||
* @return 客户端配置副本
|
||||
*/
|
||||
@Override
|
||||
public OssClientConfig config() {
|
||||
// 仅返回copy副本,防篡改
|
||||
return this.config.copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断客户端是否已经初始化。
|
||||
*
|
||||
* @return 是否已初始化
|
||||
*/
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化底层 S3 客户端资源。
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
// 如果已经是初始化状态,则直接返回
|
||||
@@ -131,24 +152,52 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行客户端具体初始化逻辑。
|
||||
*/
|
||||
abstract void doInitialize();
|
||||
|
||||
/**
|
||||
* 使用回调校验当前客户端配置。
|
||||
*
|
||||
* @param verifyConfigAction 配置校验回调
|
||||
* @return 是否校验通过
|
||||
*/
|
||||
@Override
|
||||
public boolean verifyConfig(Function<OssClientConfig, Boolean> verifyConfigAction) {
|
||||
OssClientConfig config = config();
|
||||
return Boolean.TRUE.equals(verifyConfigAction.apply(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验当前客户端配置是否与指定配置一致。
|
||||
*
|
||||
* @param verifyConfig 待校验配置
|
||||
* @return 是否一致
|
||||
*/
|
||||
@Override
|
||||
public boolean verifyConfig(OssClientConfig verifyConfig) {
|
||||
return verifyConfig((config) -> Objects.equals(config, verifyConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件名构建对象键。
|
||||
*
|
||||
* @param fileName 原始文件名
|
||||
* @return 对象键
|
||||
*/
|
||||
@Override
|
||||
public String buildPathKey(String fileName) {
|
||||
return buildPathKey(null, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据业务前缀和文件名构建对象键。
|
||||
*
|
||||
* @param businessPrefix 业务前缀
|
||||
* @param fileName 原始文件名
|
||||
* @return 对象键
|
||||
*/
|
||||
@Override
|
||||
public String buildPathKey(String businessPrefix, String fileName) {
|
||||
String defaultPrefix = config.prefix()
|
||||
@@ -161,6 +210,16 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return path + suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行自定义上传请求。
|
||||
*
|
||||
* @param body 上传请求体
|
||||
* @param putObjectRequestBuilderConsumer PutObject 请求构建回调
|
||||
* @param transferListeners 传输监听器集合
|
||||
* @param handleAsyncAction 上传完成处理函数
|
||||
* @param <T> 返回值类型
|
||||
* @return 上传处理结果
|
||||
*/
|
||||
@Override
|
||||
public <T> T doCustomUpload(AsyncRequestBody body, Consumer<PutObjectRequest.Builder> putObjectRequestBuilderConsumer, Collection<TransferListener> transferListeners, BiFunction<CompletedUpload, Throwable, T> handleAsyncAction) {
|
||||
try {
|
||||
@@ -177,11 +236,28 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行自定义上传请求。
|
||||
*
|
||||
* @param body 上传请求体
|
||||
* @param putObjectRequestBuilderConsumer PutObject 请求构建回调
|
||||
* @param handleAsyncAction 上传完成处理函数
|
||||
* @param <T> 返回值类型
|
||||
* @return 上传处理结果
|
||||
*/
|
||||
@Override
|
||||
public <T> T doCustomUpload(AsyncRequestBody body, Consumer<PutObjectRequest.Builder> putObjectRequestBuilderConsumer, BiFunction<CompletedUpload, Throwable, T> handleAsyncAction) {
|
||||
return doCustomUpload(body, putObjectRequestBuilderConsumer, null, handleAsyncAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行自定义上传请求并返回统一异步结果。
|
||||
*
|
||||
* @param body 上传请求体
|
||||
* @param putObjectRequestBuilderConsumer PutObject 请求构建回调
|
||||
* @param transferListeners 传输监听器集合
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public HandleAsyncResult<PutObjectResponse> doCustomUpload(AsyncRequestBody body, Consumer<PutObjectRequest.Builder> putObjectRequestBuilderConsumer, Collection<TransferListener> transferListeners) {
|
||||
return doCustomUpload(body, putObjectRequestBuilderConsumer, transferListeners, (completedUpload, throwable) -> {
|
||||
@@ -192,6 +268,13 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行自定义上传请求并返回统一异步结果。
|
||||
*
|
||||
* @param body 上传请求体
|
||||
* @param putObjectRequestBuilderConsumer PutObject 请求构建回调
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public HandleAsyncResult<PutObjectResponse> doCustomUpload(AsyncRequestBody body, Consumer<PutObjectRequest.Builder> putObjectRequestBuilderConsumer) {
|
||||
return doCustomUpload(body, putObjectRequestBuilderConsumer, null, (completedUpload, throwable) -> {
|
||||
@@ -202,28 +285,71 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传本地路径文件到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param path 文件路径
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, Path path, Options options) {
|
||||
AsyncRequestBody body = AsyncRequestBody.fromFile(path);
|
||||
return bucketUpload(bucket, key, body, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传本地路径文件到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param path 文件路径
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, Path path) {
|
||||
return bucketUpload(bucket, key, path, Options.builder());
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param file 文件对象
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, File file, Options options) {
|
||||
AsyncRequestBody body = AsyncRequestBody.fromFile(file);
|
||||
return bucketUpload(bucket, key, body, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param file 文件对象
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, File file) {
|
||||
return bucketUpload(bucket, key, file, Options.builder());
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传随机访问文件到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param file 随机访问文件
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, RandomAccessFile file, Options options) {
|
||||
try {
|
||||
@@ -235,11 +361,29 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传随机访问文件到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param file 随机访问文件
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, RandomAccessFile file) {
|
||||
return bucketUpload(bucket, key, file, Options.builder());
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传可读通道数据到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param channel 可读通道
|
||||
* @param contentLength 内容长度
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, ReadableByteChannel channel, long contentLength, Options options) {
|
||||
// 让调用者自行处理通道的关闭
|
||||
@@ -256,11 +400,30 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传可读通道数据到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param channel 可读通道
|
||||
* @param contentLength 内容长度
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, ReadableByteChannel channel, long contentLength) {
|
||||
return bucketUpload(bucket, key, channel, contentLength, Options.builder());
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传输入流数据到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param in 输入流
|
||||
* @param contentLength 内容长度
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, InputStream in, long contentLength, Options options) {
|
||||
options.setLength(contentLength);
|
||||
@@ -268,11 +431,29 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return bucketUpload(bucket, key, body, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传输入流数据到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param in 输入流
|
||||
* @param contentLength 内容长度
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, InputStream in, long contentLength) {
|
||||
return bucketUpload(bucket, key, in, contentLength, Options.builder());
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传字节数组到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param data 字节数组
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, byte[] data, Options options) {
|
||||
try (ByteArrayInputStream in = new ByteArrayInputStream(data)) {
|
||||
@@ -282,11 +463,28 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传字节数组到指定存储桶。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param data 字节数组
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult bucketUpload(String bucket, String key, byte[] data) {
|
||||
return bucketUpload(bucket, key, data, Options.builder());
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行指定存储桶的底层上传。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param body 上传请求体
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@NullMarked
|
||||
private PutObjectResult bucketUpload(String bucket, String key, AsyncRequestBody body, Options options) {
|
||||
// 优先使用body中的内容大小,如果不存在,再获取可选项中的
|
||||
@@ -321,6 +519,15 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return PutObjectResult.form("%s/%s".formatted(bucketUrl, key), key, response.eTag(), size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行自定义下载请求。
|
||||
*
|
||||
* @param getObjectRequestBuilderConsumer GetObject 请求构建回调
|
||||
* @param responseTransformer 下载响应转换器
|
||||
* @param transferListeners 传输监听器集合
|
||||
* @param <T> 下载结果类型
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public <T> T doCustomDownload(Consumer<GetObjectRequest.Builder> getObjectRequestBuilderConsumer, AsyncResponseTransformer<GetObjectResponse, T> responseTransformer, Collection<TransferListener> transferListeners) {
|
||||
try {
|
||||
@@ -338,6 +545,14 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定存储桶对象下载到订阅器。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param downloadSubscriber 下载订阅器
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult bucketDownload(String bucket, String key, OutputStreamDownloadSubscriber downloadSubscriber) {
|
||||
try {
|
||||
@@ -350,6 +565,15 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定存储桶对象下载到转换器。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param downloadTransformer 下载转换器
|
||||
* @param <T> 下载结果类型
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public <T> T bucketDownload(String bucket, String key, BiFunction<GetObjectResult, InputStream, T> downloadTransformer) {
|
||||
try (ResponseInputStream<GetObjectResponse> responseInputStream = doCustomDownload(builder -> builder.bucket(bucket).key(key), AsyncResponseTransformer.toBlockingInputStream(), null)) {
|
||||
@@ -361,6 +585,14 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定存储桶对象下载到本地路径。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param path 本地路径
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult bucketDownload(String bucket, String key, Path path) {
|
||||
try (OutputStream out = Files.newOutputStream(path)) {
|
||||
@@ -370,6 +602,14 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定存储桶对象下载到文件。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param file 本地文件
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult bucketDownload(String bucket, String key, File file) {
|
||||
try (FileOutputStream out = new FileOutputStream(file)) {
|
||||
@@ -379,21 +619,52 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定存储桶对象下载到随机访问文件。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param file 随机访问文件
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult bucketDownload(String bucket, String key, RandomAccessFile file) {
|
||||
return bucketDownload(bucket, key, file.getChannel());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定存储桶对象下载到可写通道。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param channel 可写通道
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult bucketDownload(String bucket, String key, WritableByteChannel channel) {
|
||||
return bucketDownload(bucket, key, OutputStreamDownloadSubscriber.create(channel));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定存储桶对象下载到输出流。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param out 输出流
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult bucketDownload(String bucket, String key, OutputStream out) {
|
||||
return bucketDownload(bucket, key, OutputStreamDownloadSubscriber.create(out));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 S3 响应构建下载结果。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param response S3 下载响应
|
||||
* @return 下载结果
|
||||
*/
|
||||
private GetObjectResult buildGetObjectResult(String key, GetObjectResponse response) {
|
||||
return GetObjectResult.form(
|
||||
key,
|
||||
@@ -409,6 +680,13 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定存储桶中的对象。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public boolean bucketDelete(String bucket, String key) {
|
||||
try {
|
||||
@@ -419,6 +697,14 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定存储桶对象的下载预签名 URL。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param expiredTime 过期时间
|
||||
* @return 预签名下载 URL
|
||||
*/
|
||||
@Override
|
||||
public String bucketPresignGetUrl(String bucket, String key, Duration expiredTime) {
|
||||
try {
|
||||
@@ -433,6 +719,15 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定存储桶对象的上传预签名 URL。
|
||||
*
|
||||
* @param bucket 存储桶名称
|
||||
* @param key 对象键
|
||||
* @param expiredTime 过期时间
|
||||
* @param metadata 对象元数据
|
||||
* @return 预签名上传 URL
|
||||
*/
|
||||
@Override
|
||||
public String bucketPresignPutUrl(String bucket, String key, Duration expiredTime, Map<String, String> metadata) {
|
||||
try {
|
||||
@@ -447,122 +742,299 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传本地路径文件到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param path 文件路径
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, Path path, Options options) {
|
||||
return bucketUpload(defaultBucket(), key, path, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传本地路径文件到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param path 文件路径
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, Path path) {
|
||||
return bucketUpload(defaultBucket(), key, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param file 文件对象
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, File file, Options options) {
|
||||
return bucketUpload(defaultBucket(), key, file, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param file 文件对象
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, File file) {
|
||||
return bucketUpload(defaultBucket(), key, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传随机访问文件到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param file 随机访问文件
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, RandomAccessFile file, Options options) {
|
||||
return bucketUpload(defaultBucket(), key, file, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传随机访问文件到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param file 随机访问文件
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, RandomAccessFile file) {
|
||||
return bucketUpload(defaultBucket(), key, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传可读通道数据到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param channel 可读通道
|
||||
* @param contentLength 内容长度
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, ReadableByteChannel channel, long contentLength, Options options) {
|
||||
return bucketUpload(defaultBucket(), key, channel, contentLength, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传可读通道数据到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param channel 可读通道
|
||||
* @param contentLength 内容长度
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, ReadableByteChannel channel, long contentLength) {
|
||||
return bucketUpload(defaultBucket(), key, channel, contentLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传输入流数据到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param in 输入流
|
||||
* @param contentLength 内容长度
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, InputStream in, long contentLength, Options options) {
|
||||
return bucketUpload(defaultBucket(), key, in, contentLength, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传输入流数据到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param in 输入流
|
||||
* @param contentLength 内容长度
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, InputStream in, long contentLength) {
|
||||
return bucketUpload(defaultBucket(), key, in, contentLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传字节数组到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param data 字节数组
|
||||
* @param options 上传选项
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, byte[] data, Options options) {
|
||||
return bucketUpload(defaultBucket(), key, data, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传字节数组到默认存储桶。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param data 字节数组
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public PutObjectResult upload(String key, byte[] data) {
|
||||
return bucketUpload(defaultBucket(), key, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将默认存储桶对象下载到订阅器。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param downloadSubscriber 下载订阅器
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult download(String key, OutputStreamDownloadSubscriber downloadSubscriber) {
|
||||
return bucketDownload(defaultBucket(), key, downloadSubscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将默认存储桶对象下载到转换器。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param downloadTransformer 下载转换器
|
||||
* @param <T> 下载结果类型
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public <T> T download(String key, BiFunction<GetObjectResult, InputStream, T> downloadTransformer) {
|
||||
return bucketDownload(defaultBucket(), key, downloadTransformer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将默认存储桶对象下载到本地路径。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param path 本地路径
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult download(String key, Path path) {
|
||||
return bucketDownload(defaultBucket(), key, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将默认存储桶对象下载到文件。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param file 本地文件
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult download(String key, File file) {
|
||||
return bucketDownload(defaultBucket(), key, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将默认存储桶对象下载到随机访问文件。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param file 随机访问文件
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult download(String key, RandomAccessFile file) {
|
||||
return bucketDownload(defaultBucket(), key, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将默认存储桶对象下载到可写通道。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param channel 可写通道
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult download(String key, WritableByteChannel channel) {
|
||||
return bucketDownload(defaultBucket(), key, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将默认存储桶对象下载到输出流。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param out 输出流
|
||||
* @return 下载结果
|
||||
*/
|
||||
@Override
|
||||
public GetObjectResult download(String key, OutputStream out) {
|
||||
return bucketDownload(defaultBucket(), key, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除默认存储桶中的对象。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(String key) {
|
||||
return bucketDelete(defaultBucket(), key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成默认存储桶对象的下载预签名 URL。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param expiredTime 过期时间
|
||||
* @return 预签名下载 URL
|
||||
*/
|
||||
@Override
|
||||
public String presignGetUrl(String key, Duration expiredTime) {
|
||||
return bucketPresignGetUrl(defaultBucket(), key, expiredTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成默认存储桶对象的上传预签名 URL。
|
||||
*
|
||||
* @param key 对象键
|
||||
* @param expiredTime 过期时间
|
||||
* @param metadata 对象元数据
|
||||
* @return 预签名上传 URL
|
||||
*/
|
||||
@Override
|
||||
public String presignPutUrl(String key, Duration expiredTime, Map<String, String> metadata) {
|
||||
return bucketPresignPutUrl(defaultBucket(), key, expiredTime, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认存储桶名称。
|
||||
*
|
||||
* @return 默认存储桶名称
|
||||
*/
|
||||
private String defaultBucket() {
|
||||
return config.bucket()
|
||||
.filter(bucket -> !bucket.isBlank())
|
||||
.orElseThrow(() -> S3StorageException.form("bucket is not configured."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并默认前缀与业务前缀。
|
||||
*
|
||||
* @param defaultPrefix 默认前缀
|
||||
* @param businessPrefix 业务前缀
|
||||
* @return 合并后的前缀
|
||||
*/
|
||||
private String mergePrefix(String defaultPrefix, String businessPrefix) {
|
||||
String left = normalizePrefix(defaultPrefix);
|
||||
String right = normalizePrefix(businessPrefix);
|
||||
@@ -575,6 +1047,12 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return left + StringUtils.SLASH + right;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化对象键前缀。
|
||||
*
|
||||
* @param prefix 原始前缀
|
||||
* @return 规范化后的前缀
|
||||
*/
|
||||
private String normalizePrefix(String prefix) {
|
||||
if (prefix == null) {
|
||||
return "";
|
||||
@@ -589,6 +1067,12 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取文件扩展名。
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 文件扩展名
|
||||
*/
|
||||
private String suffix(String fileName) {
|
||||
if (fileName == null) {
|
||||
return "";
|
||||
@@ -600,6 +1084,12 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return fileName.substring(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为统一的 S3 存储异常。
|
||||
*
|
||||
* @param e 原始异常
|
||||
* @return S3 存储异常
|
||||
*/
|
||||
private S3StorageException toStorageException(Throwable e) {
|
||||
Throwable cause = unwrapAsyncException(e);
|
||||
if (cause instanceof S3StorageException ex) {
|
||||
@@ -608,6 +1098,12 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return S3StorageException.form(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解包异步执行异常。
|
||||
*
|
||||
* @param e 原始异常
|
||||
* @return 根因异常
|
||||
*/
|
||||
private Throwable unwrapAsyncException(Throwable e) {
|
||||
Throwable cause = e;
|
||||
while ((cause instanceof CompletionException || cause instanceof ExecutionException) && cause.getCause() != null) {
|
||||
@@ -616,6 +1112,11 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭底层 S3 客户端资源。
|
||||
*
|
||||
* @throws Exception 关闭资源异常
|
||||
*/
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (s3TransferManager != null) {
|
||||
|
||||
+3
@@ -35,6 +35,9 @@ public class DefaultOssClientImpl extends AbstractOssClientImpl {
|
||||
super(clientId, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化默认 S3 客户端、传输管理器和预签名生成器。
|
||||
*/
|
||||
@Override
|
||||
void doInitialize() {
|
||||
// 校验配置
|
||||
|
||||
+15
@@ -32,17 +32,32 @@ public record AccessControlPolicyConfig(
|
||||
.accessPolicy(AccessPolicy.PUBLIC_READ_WRITE)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* 获取访问策略,未配置时返回默认策略。
|
||||
*
|
||||
* @return 访问策略
|
||||
*/
|
||||
@Override
|
||||
public @NonNull AccessPolicy accessPolicy() {
|
||||
return Optional.ofNullable(accessPolicy)
|
||||
.orElse(AccessPolicy.PUBLIC_READ_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制访问策略配置。
|
||||
*
|
||||
* @return 配置副本
|
||||
*/
|
||||
@Override
|
||||
public AccessControlPolicyConfig copy() {
|
||||
return toBuilder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为构建器。
|
||||
*
|
||||
* @return 配置构建器
|
||||
*/
|
||||
@Override
|
||||
public AccessControlPolicyConfigBuilder toBuilder() {
|
||||
return builder()
|
||||
|
||||
+10
@@ -52,11 +52,21 @@ public record OssAsyncExecutorConfig(
|
||||
return corePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制异步执行器配置。
|
||||
*
|
||||
* @return 配置副本
|
||||
*/
|
||||
@Override
|
||||
public OssAsyncExecutorConfig copy() {
|
||||
return toBuilder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为构建器。
|
||||
*
|
||||
* @return 配置构建器
|
||||
*/
|
||||
@Override
|
||||
public OssAsyncExecutorConfigBuilder toBuilder() {
|
||||
return builder()
|
||||
|
||||
+34
@@ -226,6 +226,12 @@ public class OssClientConfig implements Config<OssClientConfig, OssClientConfig.
|
||||
return usePathStyleAccess ? BucketUrlUtil.getPathStyleBucketUrl(useHttps, url, bucket) : BucketUrlUtil.getSiteStyleBucketUrl(useHttps, url, bucket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 S3 Region。
|
||||
*
|
||||
* @param regionString Region 字符串
|
||||
* @return Region 对象
|
||||
*/
|
||||
private static Region parseRegion(String regionString) {
|
||||
if (StringUtils.isBlank(regionString)) {
|
||||
return Region.US_EAST_1;
|
||||
@@ -233,11 +239,23 @@ public class OssClientConfig implements Config<OssClientConfig, OssClientConfig.
|
||||
return Region.of(regionString);
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧配置推断是否使用路径风格访问。
|
||||
*
|
||||
* @param properties OSS 配置属性
|
||||
* @return 是否使用路径风格访问
|
||||
*/
|
||||
private static boolean resolvePathStyleAccess(OssProperties properties) {
|
||||
// 旧配置没有显式路径风格字段,只能继续按内置云厂商 endpoint 做兼容推断。
|
||||
return !StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 ACL 访问策略配置。
|
||||
*
|
||||
* @param accessPolicyString 访问策略字符串
|
||||
* @return ACL 访问策略配置
|
||||
*/
|
||||
private static AccessControlPolicyConfig resolveAccessControlPolicy(String accessPolicyString) {
|
||||
// 绝大多数云厂商不允许操作 ACL,默认禁用;当前业务只用访问策略判断是否生成预签名 URL。
|
||||
if (StringUtils.isBlank(accessPolicyString)) {
|
||||
@@ -249,18 +267,34 @@ public class OssClientConfig implements Config<OssClientConfig, OssClientConfig.
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用于访问对象的基础 URL。
|
||||
*
|
||||
* @return 基础 URL
|
||||
*/
|
||||
private String getAccessBaseUrl() {
|
||||
return domain()
|
||||
.filter(OssClientConfig::hasHttpHeader)
|
||||
.orElseGet(this::getEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 endpoint 配置。
|
||||
*
|
||||
* @return endpoint
|
||||
*/
|
||||
private String getEndpoint() {
|
||||
return endpoint()
|
||||
.filter(s -> !s.isBlank())
|
||||
.orElseThrow(() -> S3StorageException.form("endpoint is not configured."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 URL 是否包含 HTTP 协议头。
|
||||
*
|
||||
* @param url URL
|
||||
* @return 是否包含 HTTP 协议头
|
||||
*/
|
||||
private static boolean hasHttpHeader(String url) {
|
||||
return HttpUtil.isHttp(url) || HttpUtil.isHttps(url);
|
||||
}
|
||||
|
||||
+12
@@ -92,10 +92,22 @@ public class OssFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定配置键对应的客户端锁。
|
||||
*
|
||||
* @param configKey 配置键
|
||||
* @return 客户端锁
|
||||
*/
|
||||
private static ReentrantLock getClientLock(String configKey) {
|
||||
return CLIENT_LOCKS.computeIfAbsent(configKey, key -> new ReentrantLock());
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭 OSS 客户端。
|
||||
*
|
||||
* @param configKey 配置键
|
||||
* @param client OSS 客户端
|
||||
*/
|
||||
private static void closeClient(String configKey, OssClient client) {
|
||||
try {
|
||||
client.close();
|
||||
|
||||
+22
@@ -20,11 +20,23 @@ public class OutputStreamDownloadSubscriber implements Consumer<ByteBuffer>, Aut
|
||||
|
||||
private final boolean allowAutoClose;
|
||||
|
||||
/**
|
||||
* 创建输出流下载订阅器。
|
||||
*
|
||||
* @param channel 可写通道
|
||||
* @param allowAutoClose 是否允许自动关闭通道
|
||||
*/
|
||||
private OutputStreamDownloadSubscriber(WritableByteChannel channel, boolean allowAutoClose) {
|
||||
this.channel = channel;
|
||||
this.allowAutoClose = allowAutoClose;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建输出流下载订阅器。
|
||||
*
|
||||
* @param out 输出流
|
||||
* @param allowAutoClose 是否允许自动关闭流
|
||||
*/
|
||||
private OutputStreamDownloadSubscriber(OutputStream out, boolean allowAutoClose) {
|
||||
this.allowAutoClose = allowAutoClose;
|
||||
// 创建可写入的字节通道
|
||||
@@ -36,6 +48,11 @@ public class OutputStreamDownloadSubscriber implements Consumer<ByteBuffer>, Aut
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入下载到的字节缓冲区。
|
||||
*
|
||||
* @param byteBuffer 字节缓冲区
|
||||
*/
|
||||
@Override
|
||||
public void accept(ByteBuffer byteBuffer) {
|
||||
try {
|
||||
@@ -47,6 +64,11 @@ public class OutputStreamDownloadSubscriber implements Consumer<ByteBuffer>, Aut
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按配置关闭底层通道。
|
||||
*
|
||||
* @throws Exception 关闭通道异常
|
||||
*/
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (channel.isOpen() && allowAutoClose) {
|
||||
|
||||
Reference in New Issue
Block a user