更新后的storageAdapter

This commit is contained in:
2025-07-21 23:32:25 +08:00
parent a425c155d0
commit 22dea22fc1
3 changed files with 401 additions and 76 deletions

View File

@@ -33,25 +33,37 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
final public class AliOssAdapter extends AStorageAdapter { final public class AliOssAdapter extends AStorageAdapter {
private AliOssStorageConfig config; private volatile AliOssStorageConfig config;
private volatile OSS ossClient;
private final Object clientLock = new Object();
private final Object configLock = new Object();
@Override @Override
public String identity() { public String identity() {
return config.identity(); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
return "ALI_OSS_UNCONFIGURED";
}
return currentConfig.identity();
} }
@Override @Override
public void loadConfig(Map<String, String> _config) { public void loadConfig(Map<String, String> _config) {
AliOssStorageConfig config = new AliOssStorageConfig(); AliOssStorageConfig newConfig = new AliOssStorageConfig();
config.setAccessKeyId(_config.get("accessKeyId")); newConfig.setAccessKeyId(_config.get("accessKeyId"));
config.setAccessKeySecret(_config.get("accessKeySecret")); newConfig.setAccessKeySecret(_config.get("accessKeySecret"));
config.setBucketName(_config.get("bucketName")); newConfig.setBucketName(_config.get("bucketName"));
config.setEndpoint(_config.get("endpoint")); newConfig.setEndpoint(_config.get("endpoint"));
config.setRegion(_config.get("region")); newConfig.setRegion(_config.get("region"));
config.setUrl(_config.get("url")); newConfig.setUrl(_config.get("url"));
config.setPrefix(_config.get("prefix")); newConfig.setPrefix(_config.get("prefix"));
config.checkEverythingOK(); newConfig.checkEverythingOK();
this.config = config;
synchronized (configLock) {
this.config = newConfig;
// 配置更新后,需要重置客户端连接
resetClient();
}
} }
@Override @Override
@@ -59,11 +71,15 @@ final public class AliOssAdapter extends AStorageAdapter {
if (config == null) { if (config == null) {
throw new StorageConfigException("配置为空"); throw new StorageConfigException("配置为空");
} }
if (config instanceof AliOssStorageConfig) { if (!(config instanceof AliOssStorageConfig)) {
this.config = (AliOssStorageConfig) config;
} else {
throw new StorageConfigException("配置类型错误,传入的类为:" + config.getClass().getName()); throw new StorageConfigException("配置类型错误,传入的类为:" + config.getClass().getName());
} }
synchronized (configLock) {
this.config = (AliOssStorageConfig) config;
// 配置更新后,需要重置客户端连接
resetClient();
}
} }
@Override @Override
@@ -75,12 +91,25 @@ final public class AliOssAdapter extends AStorageAdapter {
try (OSSWrapper wrapper = getOssClient()) { try (OSSWrapper wrapper = getOssClient()) {
OSS ossClient = wrapper.getOSSClient(); OSS ossClient = wrapper.getOSSClient();
ObjectMetadata metadata = new ObjectMetadata(); ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(inputStream.available());
// 读取完整内容并计算实际长度
byte[] bytes = inputStream.readAllBytes();
metadata.setContentLength(bytes.length);
if (StringUtils.isNotBlank(contentType)) { if (StringUtils.isNotBlank(contentType)) {
metadata.setContentType(contentType); metadata.setContentType(contentType);
} }
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, inputStream);
ossClient.putObject(putObjectRequest); // 使用字节数组创建新的 InputStream
try (InputStream byteInputStream = new java.io.ByteArrayInputStream(bytes)) {
AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
throw new StorageConfigException("存储适配器未配置");
}
PutObjectRequest putObjectRequest = new PutObjectRequest(currentConfig.getBucketName(), fullPath, byteInputStream, metadata);
ossClient.putObject(putObjectRequest);
}
return getUrl(path); return getUrl(path);
} catch (Exception e) { } catch (Exception e) {
throw new UploadFileFailedException("上传文件失败:" + e.getMessage()); throw new UploadFileFailedException("上传文件失败:" + e.getMessage());
@@ -92,7 +121,11 @@ final public class AliOssAdapter extends AStorageAdapter {
public boolean deleteFile(String... path) { public boolean deleteFile(String... path) {
try (OSSWrapper wrapper = getOssClient()) { try (OSSWrapper wrapper = getOssClient()) {
OSS ossClient = wrapper.getOSSClient(); OSS ossClient = wrapper.getOSSClient();
ossClient.deleteObject(config.getBucketName(), buildPath(path)); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
return false;
}
ossClient.deleteObject(currentConfig.getBucketName(), buildPath(path));
return true; return true;
} catch (ClientException e) { } catch (ClientException e) {
return false; return false;
@@ -101,14 +134,22 @@ final public class AliOssAdapter extends AStorageAdapter {
@Override @Override
public String getUrl(String... path) { public String getUrl(String... path) {
return config.getUrl() + "/" + buildPath(path); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
throw new StorageConfigException("存储适配器未配置");
}
return currentConfig.getUrl() + "/" + buildPath(path);
} }
@Override @Override
public String getUrlForDownload(Date expireDate, String... path) { public String getUrlForDownload(Date expireDate, String... path) {
try (OSSWrapper wrapper = getOssClient()) { try (OSSWrapper wrapper = getOssClient()) {
OSS ossClient = wrapper.getOSSClient(); OSS ossClient = wrapper.getOSSClient();
URL url = ossClient.generatePresignedUrl(config.getBucketName(), buildPath(path), expireDate, HttpMethod.GET); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
throw new StorageConfigException("存储适配器未配置");
}
URL url = ossClient.generatePresignedUrl(currentConfig.getBucketName(), buildPath(path), expireDate, HttpMethod.GET);
return url.toString(); return url.toString();
} }
} }
@@ -117,7 +158,11 @@ final public class AliOssAdapter extends AStorageAdapter {
public String getUrlForUpload(Date expireDate, String contentType, String... path) { public String getUrlForUpload(Date expireDate, String contentType, String... path) {
try (OSSWrapper wrapper = getOssClient()) { try (OSSWrapper wrapper = getOssClient()) {
OSS ossClient = wrapper.getOSSClient(); OSS ossClient = wrapper.getOSSClient();
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(config.getBucketName(), buildPath(path), HttpMethod.PUT); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
throw new StorageConfigException("存储适配器未配置");
}
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(currentConfig.getBucketName(), buildPath(path), HttpMethod.PUT);
if (StringUtils.isNotBlank(contentType)) { if (StringUtils.isNotBlank(contentType)) {
request.setContentType(contentType); request.setContentType(contentType);
} }
@@ -129,7 +174,11 @@ final public class AliOssAdapter extends AStorageAdapter {
@Override @Override
public List<StorageFileObject> listDir(String... path) { public List<StorageFileObject> listDir(String... path) {
ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(config.getBucketName()); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
throw new StorageConfigException("存储适配器未配置");
}
ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(currentConfig.getBucketName());
listObjectsV2Request.setPrefix(buildPath(path) + "/"); listObjectsV2Request.setPrefix(buildPath(path) + "/");
listObjectsV2Request.setMaxKeys(1000); listObjectsV2Request.setMaxKeys(1000);
boolean isTruncated = true; boolean isTruncated = true;
@@ -180,7 +229,11 @@ final public class AliOssAdapter extends AStorageAdapter {
} }
List<StorageFileObject> subList = objectList.subList(idx, idx + batchSize); List<StorageFileObject> subList = objectList.subList(idx, idx + batchSize);
idx += batchSize; idx += batchSize;
DeleteObjectsRequest request = new DeleteObjectsRequest(config.getBucketName()); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
return false;
}
DeleteObjectsRequest request = new DeleteObjectsRequest(currentConfig.getBucketName());
request.setKeys(subList.stream().map(StorageFileObject::getFullPath).collect(Collectors.toList())); request.setKeys(subList.stream().map(StorageFileObject::getFullPath).collect(Collectors.toList()));
try { try {
ossClient.deleteObjects(request); ossClient.deleteObjects(request);
@@ -208,7 +261,11 @@ final public class AliOssAdapter extends AStorageAdapter {
public boolean setAcl(StorageAcl acl, String... path) { public boolean setAcl(StorageAcl acl, String... path) {
try (OSSWrapper wrapper = getOssClient()) { try (OSSWrapper wrapper = getOssClient()) {
OSS ossClient = wrapper.getOSSClient(); OSS ossClient = wrapper.getOSSClient();
ossClient.setObjectAcl(config.getBucketName(), buildPath(path), convertAcl(acl)); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
return false;
}
ossClient.setObjectAcl(currentConfig.getBucketName(), buildPath(path), convertAcl(acl));
return true; return true;
} catch (OSSException e) { } catch (OSSException e) {
return false; return false;
@@ -219,32 +276,85 @@ final public class AliOssAdapter extends AStorageAdapter {
public boolean isExists(String ...path) { public boolean isExists(String ...path) {
try (OSSWrapper wrapper = getOssClient()) { try (OSSWrapper wrapper = getOssClient()) {
OSS ossClient = wrapper.getOSSClient(); OSS ossClient = wrapper.getOSSClient();
return ossClient.doesObjectExist(config.getBucketName(), buildPath(path)); AliOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
return false;
}
return ossClient.doesObjectExist(currentConfig.getBucketName(), buildPath(path));
} }
} }
private OSSWrapper getOssClient() { private OSSWrapper getOssClient() {
OSS ossClient = new OSSClientBuilder().build(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret()); AliOssStorageConfig currentConfig = this.config;
return new OSSWrapper(ossClient); if (currentConfig == null) {
throw new StorageConfigException("存储适配器未配置");
}
if (ossClient == null) {
synchronized (clientLock) {
if (ossClient == null) {
// 在同步块内再次检查配置,确保配置一致性
currentConfig = this.config;
if (currentConfig == null) {
throw new StorageConfigException("存储适配器未配置");
}
ossClient = new OSSClientBuilder().build(
currentConfig.getEndpoint(),
currentConfig.getAccessKeyId(),
currentConfig.getAccessKeySecret()
);
}
}
}
return new OSSWrapper(ossClient, false); // false 表示不自动关闭共享客户端
}
// 重置客户端连接(配置更新时调用)
private void resetClient() {
synchronized (clientLock) {
if (ossClient != null) {
ossClient.shutdown();
ossClient = null;
}
}
}
// 手动关闭客户端的方法,用于适配器销毁时
public void shutdown() {
synchronized (clientLock) {
if (ossClient != null) {
ossClient.shutdown();
ossClient = null;
}
}
} }
private String buildPath(String ...paths) { private String buildPath(String ...paths) {
if (StringUtils.isNotBlank(config.getPrefix())) { AliOssStorageConfig currentConfig = this.config;
return StorageUtil.joinPath(config.getPrefix(), paths); if (currentConfig != null && StringUtils.isNotBlank(currentConfig.getPrefix())) {
return StorageUtil.joinPath(currentConfig.getPrefix(), paths);
} else { } else {
return StorageUtil.joinPath(paths); return StorageUtil.joinPath(paths);
} }
} }
private String getRelativePath(String path) { private String getRelativePath(String path) {
return StorageUtil.getRelativePath(path, config.getPrefix()); AliOssStorageConfig currentConfig = this.config;
String prefix = currentConfig != null ? currentConfig.getPrefix() : null;
return StorageUtil.getRelativePath(path, prefix);
} }
public static class OSSWrapper implements AutoCloseable { public static class OSSWrapper implements AutoCloseable {
private final OSS ossClient; private final OSS ossClient;
private final boolean autoClose;
public OSSWrapper(OSS ossClient) { public OSSWrapper(OSS ossClient) {
this(ossClient, true);
}
public OSSWrapper(OSS ossClient, boolean autoClose) {
this.ossClient = ossClient; this.ossClient = ossClient;
this.autoClose = autoClose;
} }
// 提供对原始对象的方法访问 // 提供对原始对象的方法访问
@@ -254,8 +364,10 @@ final public class AliOssAdapter extends AStorageAdapter {
@Override @Override
public void close() { public void close() {
// 在此处实现资源关闭逻辑(如调用 OSS 的关闭方法) // 只有非共享客户端才自动关闭
ossClient.shutdown(); // 假设 OSS 提供 shutdown 方法关闭资源 if (autoClose && ossClient != null) {
ossClient.shutdown();
}
} }
} }
} }

View File

@@ -26,25 +26,37 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class AwsOssAdapter extends AStorageAdapter { public class AwsOssAdapter extends AStorageAdapter {
private AwsOssStorageConfig config; private volatile AwsOssStorageConfig config;
private volatile AmazonS3Client s3Client;
private final Object clientLock = new Object();
private final Object configLock = new Object();
@Override @Override
public String identity() { public String identity() {
return config.identity(); AwsOssStorageConfig currentConfig = this.config;
if (currentConfig == null) {
return "AWS_OSS_UNCONFIGURED";
}
return currentConfig.identity();
} }
@Override @Override
public void loadConfig(Map<String, String> _config) { public void loadConfig(Map<String, String> _config) {
AwsOssStorageConfig config = new AwsOssStorageConfig(); AwsOssStorageConfig newConfig = new AwsOssStorageConfig();
config.setAccessKeyId(_config.get("accessKeyId")); newConfig.setAccessKeyId(_config.get("accessKeyId"));
config.setAccessKeySecret(_config.get("accessKeySecret")); newConfig.setAccessKeySecret(_config.get("accessKeySecret"));
config.setBucketName(_config.get("bucketName")); newConfig.setBucketName(_config.get("bucketName"));
config.setEndpoint(_config.get("endpoint")); newConfig.setEndpoint(_config.get("endpoint"));
config.setRegion(_config.get("region")); newConfig.setRegion(_config.get("region"));
config.setUrl(_config.get("url")); newConfig.setUrl(_config.get("url"));
config.setPrefix(_config.get("prefix")); newConfig.setPrefix(_config.get("prefix"));
config.checkEverythingOK(); newConfig.checkEverythingOK();
this.config = config;
synchronized (configLock) {
this.config = newConfig;
// 配置更新后,需要重置客户端连接
resetClient();
}
} }
@Override @Override
@@ -52,11 +64,15 @@ public class AwsOssAdapter extends AStorageAdapter {
if (config == null) { if (config == null) {
throw new StorageConfigException("配置为空"); throw new StorageConfigException("配置为空");
} }
if (config instanceof AwsOssStorageConfig) { if (!(config instanceof AwsOssStorageConfig)) {
this.config = (AwsOssStorageConfig) config;
} else {
throw new StorageConfigException("配置类型错误,传入的类为:" + config.getClass().getName()); throw new StorageConfigException("配置类型错误,传入的类为:" + config.getClass().getName());
} }
synchronized (configLock) {
this.config = (AwsOssStorageConfig) config;
// 配置更新后,需要重置客户端连接
resetClient();
}
} }
@Override @Override
@@ -68,13 +84,22 @@ public class AwsOssAdapter extends AStorageAdapter {
try (S3Wrapper wrapper = getS3Client()) { try (S3Wrapper wrapper = getS3Client()) {
AmazonS3Client s3Client = wrapper.s3Client(); AmazonS3Client s3Client = wrapper.s3Client();
ObjectMetadata metadata = new ObjectMetadata(); ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(inputStream.available());
// 读取完整内容并计算实际长度
byte[] bytes = inputStream.readAllBytes();
metadata.setContentLength(bytes.length);
if (StringUtils.isNotBlank(contentType)) { if (StringUtils.isNotBlank(contentType)) {
metadata.setContentType(contentType); metadata.setContentType(contentType);
} }
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, inputStream, metadata);
putObjectRequest.withCannedAcl(CannedAccessControlList.PublicRead); // 设置访问权限,让所有用户都允许访问 // 使用字节数组创建新的 InputStream
s3Client.putObject(putObjectRequest); try (InputStream byteInputStream = new java.io.ByteArrayInputStream(bytes)) {
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, byteInputStream, metadata);
putObjectRequest.withCannedAcl(CannedAccessControlList.PublicRead); // 设置访问权限,让所有用户都允许访问
s3Client.putObject(putObjectRequest);
}
return getUrl(path); return getUrl(path);
} catch (Exception e) { } catch (Exception e) {
throw new UploadFileFailedException("上传文件失败:" + e.getMessage()); throw new UploadFileFailedException("上传文件失败:" + e.getMessage());
@@ -150,6 +175,7 @@ public class AwsOssAdapter extends AStorageAdapter {
object.setPath(getRelativePath(item.getKey().substring(0, item.getKey().lastIndexOf("/")))); object.setPath(getRelativePath(item.getKey().substring(0, item.getKey().lastIndexOf("/"))));
object.setName(item.getKey().substring(item.getKey().lastIndexOf("/") + 1)); object.setName(item.getKey().substring(item.getKey().lastIndexOf("/") + 1));
object.setSize(item.getSize()); object.setSize(item.getSize());
object.setModifyTime(item.getLastModified());
object.setRawObject(item); object.setRawObject(item);
return object; return object;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
@@ -220,14 +246,57 @@ public class AwsOssAdapter extends AStorageAdapter {
} }
private S3Wrapper getS3Client() { private S3Wrapper getS3Client() {
BasicAWSCredentials basicAwsCred = new BasicAWSCredentials(config.getAccessKeyId(), config.getAccessKeySecret()); AwsOssStorageConfig currentConfig = this.config;
ClientConfiguration clientConfiguration = new ClientConfiguration(); if (currentConfig == null) {
clientConfiguration.setProtocol(Protocol.HTTPS); throw new StorageConfigException("存储适配器未配置");
AmazonS3Client s3 = new AmazonS3Client(basicAwsCred,clientConfiguration); }
S3ClientOptions options = S3ClientOptions.builder().setPathStyleAccess(true).setPayloadSigningEnabled(true).disableChunkedEncoding().build();
s3.setS3ClientOptions(options); if (s3Client == null) {
s3.setEndpoint(config.getEndpoint()); synchronized (clientLock) {
return new S3Wrapper(s3); if (s3Client == null) {
// 在同步块内再次检查配置,确保配置一致性
currentConfig = this.config;
if (currentConfig == null) {
throw new StorageConfigException("存储适配器未配置");
}
BasicAWSCredentials basicAwsCred = new BasicAWSCredentials(
currentConfig.getAccessKeyId(),
currentConfig.getAccessKeySecret()
);
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setProtocol(Protocol.HTTPS);
s3Client = new AmazonS3Client(basicAwsCred, clientConfiguration);
S3ClientOptions options = S3ClientOptions.builder()
.setPathStyleAccess(true)
.setPayloadSigningEnabled(true)
.disableChunkedEncoding()
.build();
s3Client.setS3ClientOptions(options);
s3Client.setEndpoint(currentConfig.getEndpoint());
}
}
}
return new S3Wrapper(s3Client, false); // false 表示不自动关闭共享客户端
}
// 重置客户端连接(配置更新时调用)
private void resetClient() {
synchronized (clientLock) {
if (s3Client != null) {
s3Client.shutdown();
s3Client = null;
}
}
}
// 手动关闭客户端的方法,用于适配器销毁时
public void shutdown() {
synchronized (clientLock) {
if (s3Client != null) {
s3Client.shutdown();
s3Client = null;
}
}
} }
private String buildPath(String... paths) { private String buildPath(String... paths) {
@@ -242,10 +311,18 @@ public class AwsOssAdapter extends AStorageAdapter {
return StorageUtil.getRelativePath(path, config.getPrefix()); return StorageUtil.getRelativePath(path, config.getPrefix());
} }
public record S3Wrapper(AmazonS3Client s3Client) implements AutoCloseable { public record S3Wrapper(AmazonS3Client s3Client, boolean autoClose) implements AutoCloseable {
public S3Wrapper(AmazonS3Client s3Client) {
this(s3Client, true);
}
@Override @Override
public void close() { public void close() {
s3Client.shutdown(); // 只有非共享客户端才自动关闭
if (autoClose && s3Client != null) {
s3Client.shutdown();
}
} }
} }
} }

View File

@@ -3,71 +3,207 @@ package com.ycwl.basic.storage.adapters;
import com.ycwl.basic.storage.entity.StorageConfig; import com.ycwl.basic.storage.entity.StorageConfig;
import com.ycwl.basic.storage.entity.StorageFileObject; import com.ycwl.basic.storage.entity.StorageFileObject;
import com.ycwl.basic.storage.enums.StorageAcl; import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.storage.exceptions.StorageConfigException;
import com.ycwl.basic.storage.exceptions.StorageException;
import com.ycwl.basic.storage.exceptions.UploadFileFailedException;
import com.ycwl.basic.storage.utils.StorageUtil;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections; import java.nio.file.*;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream;
public class LocalStorageAdapter extends AStorageAdapter {
private volatile String basePath;
private volatile String baseUrl;
private volatile String prefix = "";
private final Object configLock = new Object();
public class LocalStorageAdapter extends AStorageAdapter{
@Override @Override
public String identity() { public String identity() {
return ""; return "LOCAL_STORAGE";
} }
@Override @Override
public void loadConfig(Map<String, String> config) { public void loadConfig(Map<String, String> config) {
String newBasePath = config.get("basePath");
String newBaseUrl = config.get("baseUrl");
String newPrefix = StringUtils.isNotBlank(config.get("prefix")) ? config.get("prefix") : "";
if (StringUtils.isBlank(newBasePath)) {
throw new StorageConfigException("本地存储配置错误:basePath 不能为空");
}
if (StringUtils.isBlank(newBaseUrl)) {
throw new StorageConfigException("本地存储配置错误:baseUrl 不能为空");
}
// 确保基础目录存在
try {
Files.createDirectories(Paths.get(newBasePath));
} catch (IOException e) {
throw new StorageConfigException("创建本地存储目录失败:" + e.getMessage());
}
synchronized (configLock) {
this.basePath = newBasePath;
this.baseUrl = newBaseUrl;
this.prefix = newPrefix;
}
} }
@Override @Override
public void setConfig(StorageConfig config) { public void setConfig(StorageConfig config) {
throw new StorageConfigException("LocalStorageAdapter 不支持 StorageConfig 类型配置");
} }
@Override @Override
public String uploadFile(String contentType, InputStream inputStream, String... path) { public String uploadFile(String contentType, InputStream inputStream, String... path) {
return ""; if (inputStream == null) {
return null;
}
String fullPath = buildLocalPath(path);
try {
// 确保父目录存在
Path filePath = Paths.get(fullPath);
Files.createDirectories(filePath.getParent());
// 复制文件内容到本地
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
return getUrl(path);
} catch (IOException e) {
throw new UploadFileFailedException("本地文件保存失败:" + e.getMessage());
}
} }
@Override @Override
public boolean deleteFile(String... path) { public boolean deleteFile(String... path) {
return false; try {
String fullPath = buildLocalPath(path);
return Files.deleteIfExists(Paths.get(fullPath));
} catch (IOException e) {
return false;
}
} }
@Override @Override
public String getUrl(String... path) { public String getUrl(String... path) {
return ""; String relativePath = buildRelativePath(path);
return baseUrl + "/" + relativePath;
} }
@Override @Override
public String getUrlForDownload(Date expireDate, String... path) { public String getUrlForDownload(Date expireDate, String... path) {
return ""; // 本地存储不支持带过期时间的URL,直接返回普通URL
return getUrl(path);
} }
@Override @Override
public String getUrlForUpload(Date expireDate, String contentType, String... path) { public String getUrlForUpload(Date expireDate, String contentType, String... path) {
return ""; // 本地存储不支持预签名上传URL
return getUrl(path);
} }
@Override @Override
public List<StorageFileObject> listDir(String... path) { public List<StorageFileObject> listDir(String... path) {
return Collections.emptyList(); String fullPath = buildLocalPath(path);
Path dirPath = Paths.get(fullPath);
if (!Files.exists(dirPath) || !Files.isDirectory(dirPath)) {
return new ArrayList<>();
}
List<StorageFileObject> result = new ArrayList<>();
try (Stream<Path> paths = Files.list(dirPath)) {
paths.forEach(filePath -> {
try {
StorageFileObject obj = new StorageFileObject();
obj.setName(filePath.getFileName().toString());
obj.setPath(getRelativePath(filePath.getParent().toString()));
obj.setSize(Files.size(filePath));
obj.setModifyTime(new Date(Files.getLastModifiedTime(filePath).toMillis()));
obj.setRawObject(filePath.toFile());
result.add(obj);
} catch (IOException e) {
// 忽略无法读取的文件
}
});
} catch (IOException e) {
throw new StorageException("列举本地文件失败:" + e.getMessage());
}
return result;
} }
@Override @Override
public boolean deleteDir(String... path) { public boolean deleteDir(String... path) {
return false; String fullPath = buildLocalPath(path);
Path dirPath = Paths.get(fullPath);
if (!Files.exists(dirPath)) {
return true;
}
try {
// 递归删除目录及其内容
try (Stream<Path> paths = Files.walk(dirPath)) {
paths.sorted((a, b) -> b.compareTo(a)) // 从深到浅排序,确保先删除文件再删除目录
.forEach(filePath -> {
try {
Files.deleteIfExists(filePath);
} catch (IOException e) {
// 忽略删除失败的文件
}
});
}
return !Files.exists(dirPath);
} catch (IOException e) {
return false;
}
} }
@Override @Override
public boolean setAcl(StorageAcl acl, String... path) { public boolean setAcl(StorageAcl acl, String... path) {
return false; // 本地存储不支持ACL设置
return true;
} }
@Override @Override
public boolean isExists(String... path) { public boolean isExists(String... path) {
return false; String fullPath = buildLocalPath(path);
return Files.exists(Paths.get(fullPath));
}
private String buildLocalPath(String... paths) {
String relativePath = buildRelativePath(paths);
return Paths.get(basePath, relativePath).toString();
}
private String buildRelativePath(String... paths) {
if (StringUtils.isNotBlank(prefix)) {
return StorageUtil.joinPath(prefix, paths);
} else {
return StorageUtil.joinPath(paths);
}
}
private String getRelativePath(String fullPath) {
String basePathNormalized = Paths.get(basePath).toString();
if (fullPath.startsWith(basePathNormalized)) {
String relative = fullPath.substring(basePathNormalized.length());
if (relative.startsWith(File.separator)) {
relative = relative.substring(1);
}
return StorageUtil.getRelativePath(relative, prefix);
}
return fullPath;
} }
} }