Skip to content

Commit 96e9c99

Browse files
committed
fix(storage): 修复文件名生成器和存储服务中的问题
- 修正 DefaultFileNameGenerator.getName 返回值为类名本身 - 移除 FileStorageService 中未使用的 StorageProperties 字段和相关逻辑 - 优化 LocalStorageAutoConfiguration,避免空配置时空指针异常 - 本地存储策略中加强资源映射路径的安全检查和异常处理 - OssStorageAutoConfiguration 同样添加空配置保护代码 - OssStorageStrategy 实现分片上传时根据阈值自动切换内存与临时文件存储 - 增加分片上传配置支持临时目录及请求超时配置 - OssStorageStrategy 优化 S3 客户端配置,添加请求超时和路径风格访问设置 - 改善异常捕获逻辑,区分 404 与其他错误,更准确地处理文件不存在场景 - StorageStrategyRouter 优化默认存储平台获取逻辑,支持多候选优先级排序 - StorageAutoConfiguration 简化注入,无需手动声明自动配置Bean,增强代理类注解兼容性 - UploadContext.getFullPath 方法修复处理路径和文件名拼接的空值和尾部斜杠问题
1 parent 477e82a commit 96e9c99

File tree

10 files changed

+281
-95
lines changed

10 files changed

+281
-95
lines changed

continew-starter-storage/src/main/java/top/continew/starter/storage/autoconfigure/LocalStorageAutoConfiguration.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@
1717
package top.continew.starter.storage.autoconfigure;
1818

1919
import cn.hutool.core.util.StrUtil;
20-
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
21-
import org.springframework.context.annotation.Bean;
22-
import top.continew.starter.core.constant.PropertiesConstants;
20+
import org.springframework.context.annotation.Configuration;
2321
import top.continew.starter.storage.autoconfigure.properties.LocalStorageConfig;
2422
import top.continew.starter.storage.autoconfigure.properties.StorageProperties;
2523
import top.continew.starter.storage.engine.StorageStrategyRegistrar;
2624
import top.continew.starter.storage.strategy.StorageStrategy;
2725
import top.continew.starter.storage.strategy.impl.LocalStorageStrategy;
2826

27+
import java.util.Collections;
2928
import java.util.List;
3029

3130
/**
@@ -34,7 +33,7 @@
3433
* @author echo
3534
* @since 2.14.0
3635
*/
37-
@ConditionalOnProperty(prefix = PropertiesConstants.STORAGE, name = "local")
36+
@Configuration(proxyBeanMethods = false)
3837
public class LocalStorageAutoConfiguration implements StorageStrategyRegistrar {
3938

4039
private final StorageProperties storageProperties;
@@ -48,10 +47,12 @@ public LocalStorageAutoConfiguration(StorageProperties storageProperties) {
4847
*
4948
* @param strategies 策略列表
5049
*/
51-
@Bean
5250
@Override
5351
public void register(List<StorageStrategy> strategies) {
54-
for (LocalStorageConfig config : storageProperties.getLocal()) {
52+
List<LocalStorageConfig> localConfigs = storageProperties.getLocal() == null
53+
? Collections.emptyList()
54+
: storageProperties.getLocal();
55+
for (LocalStorageConfig config : localConfigs) {
5556
if (config.isEnabled()) {
5657
if (config.getMultipartUploadThreshold() == null || config.getMultipartUploadThreshold() <= 0) {
5758
config.setMultipartUploadThreshold(storageProperties.getMultipartUploadThreshold());

continew-starter-storage/src/main/java/top/continew/starter/storage/autoconfigure/OssStorageAutoConfiguration.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@
1616

1717
package top.continew.starter.storage.autoconfigure;
1818

19-
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
20-
import org.springframework.context.annotation.Bean;
21-
import top.continew.starter.core.constant.PropertiesConstants;
19+
import org.springframework.context.annotation.Configuration;
2220
import top.continew.starter.storage.autoconfigure.properties.OssStorageConfig;
2321
import top.continew.starter.storage.autoconfigure.properties.StorageProperties;
2422
import top.continew.starter.storage.engine.StorageStrategyRegistrar;
2523
import top.continew.starter.storage.strategy.StorageStrategy;
2624
import top.continew.starter.storage.strategy.impl.OssStorageStrategy;
2725

26+
import java.util.Collections;
2827
import java.util.List;
2928

3029
/**
@@ -33,7 +32,7 @@
3332
* @author echo
3433
* @since 2.14.0
3534
*/
36-
@ConditionalOnProperty(prefix = PropertiesConstants.STORAGE, name = "oss")
35+
@Configuration(proxyBeanMethods = false)
3736
public class OssStorageAutoConfiguration implements StorageStrategyRegistrar {
3837

3938
private final StorageProperties properties;
@@ -48,9 +47,9 @@ public OssStorageAutoConfiguration(StorageProperties properties) {
4847
* @param strategies 策略列表
4948
*/
5049
@Override
51-
@Bean
5250
public void register(List<StorageStrategy> strategies) {
53-
for (OssStorageConfig config : properties.getOss()) {
51+
List<OssStorageConfig> ossConfigs = properties.getOss() == null ? Collections.emptyList() : properties.getOss();
52+
for (OssStorageConfig config : ossConfigs) {
5453
if (config.isEnabled()) {
5554
if (config.getMultipartUploadThreshold() == null || config.getMultipartUploadThreshold() <= 0) {
5655
config.setMultipartUploadThreshold(properties.getMultipartUploadThreshold());

continew-starter-storage/src/main/java/top/continew/starter/storage/autoconfigure/StorageAutoConfiguration.java

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import jakarta.annotation.PostConstruct;
2020
import org.slf4j.Logger;
2121
import org.slf4j.LoggerFactory;
22+
import org.springframework.aop.support.AopUtils;
2223
import org.springframework.boot.autoconfigure.AutoConfiguration;
2324
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2425
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -27,6 +28,7 @@
2728
import org.springframework.context.ApplicationContext;
2829
import org.springframework.context.annotation.Bean;
2930
import org.springframework.context.annotation.Import;
31+
import org.springframework.core.annotation.AnnotationUtils;
3032
import top.continew.starter.storage.annotation.PlatformProcessor;
3133
import top.continew.starter.storage.autoconfigure.properties.StorageProperties;
3234
import top.continew.starter.storage.core.FileStorageService;
@@ -51,7 +53,7 @@
5153
*/
5254
@AutoConfiguration
5355
@EnableConfigurationProperties(StorageProperties.class)
54-
@Import({ProcessorRegistry.class})
56+
@Import({OssStorageAutoConfiguration.class, LocalStorageAutoConfiguration.class})
5557
public class StorageAutoConfiguration {
5658

5759
private static final Logger log = LoggerFactory.getLogger(StorageAutoConfiguration.class);
@@ -71,8 +73,9 @@ public StorageAutoConfiguration(StorageProperties properties, ApplicationContext
7173
* @return {@link StorageStrategyRouter }
7274
*/
7375
@Bean
74-
public StorageStrategyRouter strategyRouter(List<StorageStrategyRegistrar> registrars) {
75-
return new StorageStrategyRouter(registrars, properties, storageDecoratorManager());
76+
public StorageStrategyRouter strategyRouter(List<StorageStrategyRegistrar> registrars,
77+
StorageDecoratorManager storageDecoratorManager) {
78+
return new StorageStrategyRouter(registrars, properties, storageDecoratorManager);
7679
}
7780

7881
/**
@@ -85,41 +88,19 @@ public StorageDecoratorManager storageDecoratorManager() {
8588
return new StorageDecoratorManager(applicationContext);
8689
}
8790

88-
/**
89-
* oss存储自动配置
90-
*
91-
* @return {@link OssStorageAutoConfiguration }
92-
*/
93-
@Bean
94-
public OssStorageAutoConfiguration ossStorageAutoConfiguration() {
95-
return new OssStorageAutoConfiguration(properties);
96-
}
97-
98-
/**
99-
* 本地存储自动配置
100-
*
101-
* @return {@link LocalStorageAutoConfiguration }
102-
*/
103-
@Bean
104-
public LocalStorageAutoConfiguration localStorageAutoConfiguration() {
105-
return new LocalStorageAutoConfiguration(properties);
106-
}
107-
10891
/**
10992
* 文件存储服务
11093
*
11194
* @param router 路由
112-
* @param storageProperties 存储属性
11395
* @param processorRegistry 处理器注册表
11496
* @param fileRecorder 文件记录器
11597
* @return {@link FileStorageService }
11698
*/
11799
@Bean
118100
public FileStorageService fileStorageService(StorageStrategyRouter router,
119-
StorageProperties storageProperties,
120101
ProcessorRegistry processorRegistry,
121102
FileRecorder fileRecorder) {
122-
return new FileStorageService(router, storageProperties, processorRegistry, fileRecorder);
103+
return new FileStorageService(router, processorRegistry, fileRecorder);
123104
}
124105

125106
/**
@@ -143,8 +124,9 @@ public ProcessorRegistry processorRegistry() {
143124
// 自动发现并注册所有 FileProcessor 实现
144125
Map<String, FileProcessor> processors = applicationContext.getBeansOfType(FileProcessor.class);
145126
processors.values().forEach(processor -> {
146-
// 检查是否有平台注解
147-
PlatformProcessor annotation = processor.getClass().getAnnotation(PlatformProcessor.class);
127+
// 检查是否有平台注解(兼容代理类)
128+
Class<?> targetClass = AopUtils.getTargetClass(processor);
129+
PlatformProcessor annotation = AnnotationUtils.findAnnotation(targetClass, PlatformProcessor.class);
148130
if (annotation != null) {
149131
for (String platform : annotation.platforms()) {
150132
registry.register(processor, platform);

continew-starter-storage/src/main/java/top/continew/starter/storage/autoconfigure/properties/OssStorageConfig.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ public class OssStorageConfig {
8181
*/
8282
private Long multipartUploadPartSize;
8383

84+
/**
85+
* 分片落盘临时目录(可选)
86+
*/
87+
private String multipartTempDir;
88+
8489
/**
8590
* 请求超时时间(秒)
8691
*/
@@ -184,6 +189,14 @@ public void setMultipartUploadPartSize(Long multipartUploadPartSize) {
184189
this.multipartUploadPartSize = multipartUploadPartSize;
185190
}
186191

192+
public String getMultipartTempDir() {
193+
return multipartTempDir;
194+
}
195+
196+
public void setMultipartTempDir(String multipartTempDir) {
197+
this.multipartTempDir = multipartTempDir;
198+
}
199+
187200
public int getRequestTimeout() {
188201
return requestTimeout;
189202
}

continew-starter-storage/src/main/java/top/continew/starter/storage/core/FileStorageService.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import org.slf4j.LoggerFactory;
2222
import org.springframework.web.multipart.MultipartFile;
2323
import top.continew.starter.core.constant.StringConstants;
24-
import top.continew.starter.storage.autoconfigure.properties.StorageProperties;
2524
import top.continew.starter.storage.common.constant.StorageConstant;
2625
import top.continew.starter.storage.common.exception.StorageException;
2726
import top.continew.starter.storage.domain.file.EnhancedMultipartFile;
@@ -56,18 +55,15 @@ public class FileStorageService {
5655
private static final Logger log = LoggerFactory.getLogger(FileStorageService.class);
5756

5857
private final StorageStrategyRouter router;
59-
private final StorageProperties storageProperties;
6058
private final ProcessorRegistry processorRegistry;
6159
private final FileRecorder fileRecorder;
6260
private final ThreadLocal<List<FileProcessor>> tempProcessors = ThreadLocal.withInitial(ArrayList::new);
6361
private final ThreadLocal<UploadProgressListener> progressListener = new ThreadLocal<>();
6462

6563
public FileStorageService(StorageStrategyRouter router,
66-
StorageProperties storageProperties,
6764
ProcessorRegistry processorRegistry,
6865
FileRecorder fileRecorder) {
6966
this.router = router;
70-
this.storageProperties = storageProperties;
7167
this.processorRegistry = processorRegistry;
7268
this.fileRecorder = fileRecorder;
7369
}
@@ -600,8 +596,6 @@ public FileInfo completeMultipartUpload(String platform,
600596
.getOriginalFileName()));
601597
fileInfo.getMetadata()
602598
.put("fileMd5", StrUtil.blankToDefault(session.getFileMd5(), StringConstants.EMPTY));
603-
fileInfo.getMetadata()
604-
.put("sha256", StrUtil.blankToDefault(session.getFileMd5(), StringConstants.EMPTY));
605599
}
606600
fileInfo.getMetadata().put("uploadId", uploadId);
607601
fileInfo.getMetadata().put("status", "COMPLETED");

continew-starter-storage/src/main/java/top/continew/starter/storage/domain/model/context/UploadContext.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package top.continew.starter.storage.domain.model.context;
1818

1919
import org.springframework.web.multipart.MultipartFile;
20+
import top.continew.starter.core.constant.StringConstants;
2021
import top.continew.starter.storage.domain.model.req.ThumbnailSize;
2122
import top.continew.starter.storage.processor.progress.UploadProgressListener;
2223

@@ -85,7 +86,18 @@ public class UploadContext {
8586
* 获取完整路径
8687
*/
8788
public String getFullPath() {
88-
return path + formatFileName;
89+
String safePath = path == null ? "" : path.trim();
90+
String safeFileName = formatFileName == null ? "" : formatFileName.trim();
91+
92+
if (safePath.isEmpty()) {
93+
return safeFileName;
94+
}
95+
if (safeFileName.isEmpty()) {
96+
return safePath;
97+
}
98+
return safePath.endsWith(StringConstants.SLASH)
99+
? safePath + safeFileName
100+
: safePath + StringConstants.SLASH + safeFileName;
89101
}
90102

91103
public MultipartFile getFile() {

continew-starter-storage/src/main/java/top/continew/starter/storage/engine/StorageStrategyRouter.java

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -148,28 +148,66 @@ public void onApplicationEvent(ApplicationEvent event) {
148148
* 注册动态默认存储
149149
*/
150150
public void registerDynamicDefaultStorage(String platform) {
151-
this.dynamicDefaultPlatform = platform;
151+
this.dynamicDefaultPlatform = StrUtil.isBlank(platform) ? null : platform.trim();
152152
}
153153

154154
/**
155155
* 获取默认存储平台
156156
*/
157157
public String getDefaultStorage() {
158-
DefaultStorageSource defaultStorageSource = storageProperties.getDefaultStorageSource();
159-
return switch (defaultStorageSource) {
160-
case DYNAMIC -> {
161-
if (StrUtil.isBlank(dynamicDefaultPlatform)) {
162-
throw new StorageException("动态默认存储平台配置为空");
163-
}
164-
yield dynamicDefaultPlatform;
158+
DefaultStorageSource defaultStorageSource = ObjectUtil.defaultIfNull(storageProperties
159+
.getDefaultStorageSource(), DefaultStorageSource.DYNAMIC);
160+
List<String> candidates = resolveDefaultStorageCandidates(defaultStorageSource);
161+
for (String candidate : candidates) {
162+
if (hasStrategy(candidate)) {
163+
return candidate;
165164
}
166-
case CONFIG -> {
167-
if (StrUtil.isBlank(configDefaultPlatform)) {
168-
throw new StorageException("配置默认存储平台配置为空");
169-
}
170-
yield configDefaultPlatform;
171-
}
172-
};
165+
}
166+
167+
throw new StorageException(String
168+
.format("未找到可用默认存储平台: source=%s, candidates=%s, available=%s", defaultStorageSource, candidates, getAllPlatform()));
169+
}
170+
171+
/**
172+
* 解决默认存储候选
173+
*
174+
* @param defaultStorageSource 默认存储源
175+
* @return {@link List }<{@link String }>
176+
*/
177+
private List<String> resolveDefaultStorageCandidates(DefaultStorageSource defaultStorageSource) {
178+
Set<String> orderedCandidates = new LinkedHashSet<>();
179+
if (defaultStorageSource == DefaultStorageSource.DYNAMIC) {
180+
addCandidate(orderedCandidates, dynamicDefaultPlatform);
181+
addCandidate(orderedCandidates, configDefaultPlatform);
182+
} else {
183+
addCandidate(orderedCandidates, configDefaultPlatform);
184+
addCandidate(orderedCandidates, dynamicDefaultPlatform);
185+
}
186+
addCandidate(orderedCandidates, StorageConstant.DEFAULT_STORAGE_PLATFORM);
187+
return new ArrayList<>(orderedCandidates);
188+
}
189+
190+
/**
191+
* 添加候选人
192+
*
193+
* @param candidates 候选人
194+
* @param platform 站台
195+
*/
196+
private void addCandidate(Set<String> candidates, String platform) {
197+
String normalizedPlatform = StrUtil.trim(platform);
198+
if (StrUtil.isNotBlank(normalizedPlatform)) {
199+
candidates.add(normalizedPlatform);
200+
}
201+
}
202+
203+
/**
204+
* 有策略
205+
*
206+
* @param platform 站台
207+
* @return boolean
208+
*/
209+
private boolean hasStrategy(String platform) {
210+
return dynamicStrategies.containsKey(platform) || configStrategies.containsKey(platform);
173211
}
174212

175213
/**

continew-starter-storage/src/main/java/top/continew/starter/storage/processor/preprocess/impl/DefaultFileNameGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class DefaultFileNameGenerator implements FileNameGenerator {
3131

3232
@Override
3333
public String getName() {
34-
return DefaultFilePathGenerator.class.getSimpleName();
34+
return DefaultFileNameGenerator.class.getSimpleName();
3535
}
3636

3737
@Override

0 commit comments

Comments
 (0)