mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-03-28 16:23:24 +08:00
update 优化 oss 模块代码实现
This commit is contained in:
@@ -2,6 +2,7 @@ package org.dromara.common.oss.client;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import org.dromara.common.core.utils.DateUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.oss.config.OssClientConfig;
|
||||
import org.dromara.common.oss.exception.S3StorageException;
|
||||
@@ -127,27 +128,6 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
|
||||
abstract void doInitialize();
|
||||
|
||||
@Override
|
||||
public void refresh(OssClientConfig config) {
|
||||
if (Objects.equals(this.config, config)) {
|
||||
return;
|
||||
}
|
||||
// 如果状态本来就是未初始化,直接则调用初始化
|
||||
if (!initialized.get()) {
|
||||
this.initialize();
|
||||
}
|
||||
// 将状态转为未初始化
|
||||
if (initialized.compareAndSet(false, true)) {
|
||||
try {
|
||||
this.close();
|
||||
} catch (Exception e) {
|
||||
// 异常不影响刷新逻辑,此处屏蔽异常
|
||||
}
|
||||
// 状态交换成功才进行刷新
|
||||
this.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyConfig(Function<OssClientConfig, Boolean> verifyConfigAction) {
|
||||
OssClientConfig config = config();
|
||||
@@ -159,6 +139,23 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
return verifyConfig((config) -> Objects.equals(config, verifyConfig));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildPathKey(String fileName) {
|
||||
return buildPathKey(null, fileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildPathKey(String businessPrefix, String fileName) {
|
||||
String defaultPrefix = config.prefix()
|
||||
.orElse("");
|
||||
String mergedPrefix = mergePrefix(defaultPrefix, businessPrefix);
|
||||
String suffix = suffix(fileName);
|
||||
String datePath = DateUtils.datePath();
|
||||
String uuid = IdUtil.fastSimpleUUID();
|
||||
String path = mergedPrefix.isEmpty() ? datePath + StringUtils.SLASH + uuid : mergedPrefix + StringUtils.SLASH + datePath + StringUtils.SLASH + uuid;
|
||||
return path + suffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doCustomUpload(AsyncRequestBody body, Consumer<PutObjectRequest.Builder> putObjectRequestBuilderConsumer, Collection<TransferListener> transferListeners, BiFunction<CompletedUpload, Throwable, T> handleAsyncAction) {
|
||||
try {
|
||||
@@ -230,7 +227,7 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
try {
|
||||
// 以文件的大小为准
|
||||
options.setLength(file.length());
|
||||
return bucketUpload(bucket, key, file.getChannel(), -1L);
|
||||
return bucketUpload(bucket, key, file.getChannel(), -1L, options);
|
||||
} catch (Exception e) {
|
||||
if (e instanceof S3StorageException ex) {
|
||||
throw ex;
|
||||
@@ -438,8 +435,8 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
@Override
|
||||
public boolean bucketDelete(String bucket, String key) {
|
||||
try {
|
||||
DeleteObjectResponse response = s3AsyncClient.deleteObject(builder -> builder.bucket(bucket).key(key)).join();
|
||||
return Boolean.TRUE.equals(response.deleteMarker());
|
||||
s3AsyncClient.deleteObject(builder -> builder.bucket(bucket).key(key)).join();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
throw S3StorageException.form(e);
|
||||
}
|
||||
@@ -589,6 +586,43 @@ public abstract class AbstractOssClientImpl implements OssClient {
|
||||
.orElseThrow(() -> S3StorageException.form("bucket is not configured."));
|
||||
}
|
||||
|
||||
private String mergePrefix(String defaultPrefix, String businessPrefix) {
|
||||
String left = normalizePrefix(defaultPrefix);
|
||||
String right = normalizePrefix(businessPrefix);
|
||||
if (left.isEmpty()) {
|
||||
return right;
|
||||
}
|
||||
if (right.isEmpty()) {
|
||||
return left;
|
||||
}
|
||||
return left + StringUtils.SLASH + right;
|
||||
}
|
||||
|
||||
private String normalizePrefix(String prefix) {
|
||||
if (prefix == null) {
|
||||
return "";
|
||||
}
|
||||
String normalized = prefix.trim();
|
||||
while (normalized.startsWith(StringUtils.SLASH)) {
|
||||
normalized = normalized.substring(1);
|
||||
}
|
||||
while (normalized.endsWith(StringUtils.SLASH)) {
|
||||
normalized = normalized.substring(0, normalized.length() - 1);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private String suffix(String fileName) {
|
||||
if (fileName == null) {
|
||||
return "";
|
||||
}
|
||||
int index = fileName.lastIndexOf('.');
|
||||
if (index < 0) {
|
||||
return "";
|
||||
}
|
||||
return fileName.substring(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (s3TransferManager != null) {
|
||||
|
||||
@@ -68,13 +68,6 @@ public interface OssClient extends AutoCloseable {
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* 刷新客户端配置
|
||||
*
|
||||
* @param config 配置项
|
||||
*/
|
||||
void refresh(OssClientConfig config);
|
||||
|
||||
/**
|
||||
* 校验客户端配置
|
||||
*
|
||||
@@ -585,4 +578,21 @@ public interface OssClient extends AutoCloseable {
|
||||
* @return 预签名上传 URL
|
||||
*/
|
||||
String presignPutUrl(String key, Duration expiredTime, Map<String, String> metadata);
|
||||
|
||||
/**
|
||||
* 根据客户端配置生成默认对象Key。
|
||||
*
|
||||
* @param fileName 原始文件名
|
||||
* @return 对象Key
|
||||
*/
|
||||
String buildPathKey(String fileName);
|
||||
|
||||
/**
|
||||
* 根据业务前缀和客户端默认前缀生成对象Key。
|
||||
*
|
||||
* @param businessPrefix 业务前缀
|
||||
* @param fileName 原始文件名
|
||||
* @return 对象Key
|
||||
*/
|
||||
String buildPathKey(String businessPrefix, String fileName);
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ public class OssClientConfig implements Config<OssClientConfig, OssClientConfig.
|
||||
.secretKey(properties.getSecretKey())
|
||||
.bucket(properties.getBucketName())
|
||||
.region(region)
|
||||
.prefix(properties.getPrefix())
|
||||
.useHttps(SystemConstants.YES.equals(properties.getIsHttps()))
|
||||
.usePathStyleAccess(usePathStyleAccess)
|
||||
.accessControlPolicyConfig(accessControlPolicyConfig);
|
||||
|
||||
@@ -52,19 +52,16 @@ public class OssFactory {
|
||||
OssClientConfig config = OssClientConfig.formProperties(properties);
|
||||
LOCK.lock();
|
||||
try {
|
||||
// 如果已经存在,则校验配置一致性
|
||||
if (CLIENT_CACHE.containsKey(configKey)) {
|
||||
OssClient client = CLIENT_CACHE.get(configKey);
|
||||
if (!client.verifyConfig(config)) {
|
||||
// 配置不一致,刷新配置
|
||||
client.refresh(config);
|
||||
CLIENT_CACHE.put(configKey, client);
|
||||
OssClient client = CLIENT_CACHE.get(configKey);
|
||||
if (client != null) {
|
||||
if (client.verifyConfig(config)) {
|
||||
return client;
|
||||
}
|
||||
return client;
|
||||
closeClient(configKey, client);
|
||||
}
|
||||
DefaultOssClientImpl client = new DefaultOssClientImpl(configKey, config);
|
||||
CLIENT_CACHE.put(configKey, client);
|
||||
return client;
|
||||
OssClient newClient = new DefaultOssClientImpl(configKey, config);
|
||||
CLIENT_CACHE.put(configKey, newClient);
|
||||
return newClient;
|
||||
} finally {
|
||||
LOCK.unlock();
|
||||
}
|
||||
@@ -78,12 +75,16 @@ public class OssFactory {
|
||||
if (client == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
client.close();
|
||||
} catch (Exception e) {
|
||||
log.warn("S3存储客户端关闭异常,错误信息: {}", e.getMessage(), e);
|
||||
}
|
||||
closeClient(configKey, client);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void closeClient(String configKey, OssClient client) {
|
||||
try {
|
||||
client.close();
|
||||
} catch (Exception e) {
|
||||
log.warn("S3存储客户端 [{}] 关闭异常,错误信息: {}", configKey, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package org.dromara.common.oss.util;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.dromara.common.core.utils.DateUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* S3文件对象工具类
|
||||
*
|
||||
* @author 秋辞未寒
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class S3ObjectUtil {
|
||||
|
||||
/**
|
||||
* 生成一个 【自定义前缀 + 日期路径 + SimpleUUID.文件后缀】 的对象Key 示例: images/20260321/019d0f89c9b1130a48c90dbca0475a.jpg
|
||||
*
|
||||
* @param prefix 前缀
|
||||
* @param withSuffixFileName 带后缀的文件名
|
||||
* @return 文件路径对象Key
|
||||
*/
|
||||
public static String buildPathKey(String prefix, String withSuffixFileName) {
|
||||
// 获取后缀
|
||||
String suffix = StringUtils.substring(withSuffixFileName, withSuffixFileName.lastIndexOf("."), withSuffixFileName.length());
|
||||
// 生成日期路径
|
||||
String datePath = DateUtils.datePath();
|
||||
// 生成uuid
|
||||
String uuid = IdUtil.fastSimpleUUID();
|
||||
// 拼接路径
|
||||
String path = StringUtils.isNotEmpty(prefix) ? prefix + StringUtils.SLASH + datePath + StringUtils.SLASH + uuid : datePath + StringUtils.SLASH + uuid;
|
||||
return path + suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成一个 【日期路径 + SimpleUUID.文件后缀】 的对象Key 示例: 20260321/019d0f89c9b1130a48c90dbca0475a.jpg
|
||||
*
|
||||
* @param withSuffixFileName 带后缀的文件名
|
||||
* @return 文件路径对象Key
|
||||
*/
|
||||
public static String buildPathKey(String withSuffixFileName) {
|
||||
return buildPathKey("", withSuffixFileName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import org.dromara.common.oss.enums.AccessPolicy;
|
||||
import org.dromara.common.oss.factory.OssFactory;
|
||||
import org.dromara.common.oss.model.Options;
|
||||
import org.dromara.common.oss.model.PutObjectResult;
|
||||
import org.dromara.common.oss.util.S3ObjectUtil;
|
||||
import org.dromara.system.domain.SysOss;
|
||||
import org.dromara.system.domain.SysOssExt;
|
||||
import org.dromara.system.domain.bo.SysOssBo;
|
||||
@@ -232,11 +231,9 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
String originalfileName = file.getOriginalFilename();
|
||||
String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
|
||||
OssClient instance = OssFactory.instance();
|
||||
try {
|
||||
String pathKey = S3ObjectUtil.buildPathKey(originalfileName);
|
||||
InputStream inputStream = file.getInputStream();
|
||||
String pathKey = instance.buildPathKey(originalfileName);
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
PutObjectResult result = instance.upload(pathKey, inputStream, file.getSize(), Options.builder().setContentType(file.getContentType()));
|
||||
IoUtil.close(inputStream);
|
||||
SysOssExt ext1 = new SysOssExt();
|
||||
ext1.setFileSize(file.getSize());
|
||||
ext1.setContentType(file.getContentType());
|
||||
@@ -261,7 +258,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
String originalfileName = file.getName();
|
||||
String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
|
||||
OssClient instance = OssFactory.instance();
|
||||
String pathKey = S3ObjectUtil.buildPathKey(originalfileName);
|
||||
String pathKey = instance.buildPathKey(originalfileName);
|
||||
PutObjectResult result = instance.upload(pathKey, file, Options.builder().setContentType(FileUtils.getMimeType(file.toPath())));
|
||||
SysOssExt ext1 = new SysOssExt();
|
||||
ext1.setFileSize(result.size());
|
||||
|
||||
Reference in New Issue
Block a user