RuoYi-Geek-SpringBoot3-文件上传模块
📌 请关注开源社区Geek-XD
基于桥接模式的文件上传模块的设计与实现
摘要
本文介绍了一种基于桥接模式设计的文件上传系统架构,通过解耦存储服务与业务逻辑,实现灵活的多存储服务支持。系统包含核心类设计、工具封装和典型应用案例,适用于单服务单存储桶及多服务多存储桶的复杂业务场景。
Vue端文件上传图片
核心设计模式解析
为何选择桥接模式?
在文件上传场景中,存储服务(如OSS、S3)与存储桶配置常存在多维度组合需求。桥接模式通过将抽象(业务逻辑)与实现(存储操作)分离,有效解决了:
- 多存储服务商的适配问题
- 存储桶参数配置的灵活性
- 业务逻辑(如分片上传)与底层存储的解耦
系统核心类图谱
1. 基础对象层
类名 | 职责说明 |
---|---|
StorageBucket |
实现基础存储操作接口,包含putObject /getObject 等核心方法 |
StorageEntity |
存储元数据实体类,封装路径、大小、ETag、存储时间等属性 |
StorageManagement |
管理存储桶生命周期,提供createBucket /listBuckets 等管理接口 |
2. 工具层
工具类 | 使用场景 |
---|---|
StorageUtils |
提供存储服务实例化与存储桶获取能力,支持多存储类型动态加载 |
FileOperateUtils |
封装默认存储服务的快捷操作方法,简化单服务单存储桶场景下的开发复杂度 |
桥接模式实践
核心桥接类:StorageService
public class StorageService {
// 更多业务逻辑...
/**
* 上传文件(指定文件路径)
*
* @param filePath 指定上传文件的路径
* @param file 上传的文件
* @return 上传后的访问链接
* @throws Exception 比如读写文件出错时
*
*/
public String upload(String filePath, MultipartFile file) throws Exception {
FileUtils.assertAllowed(file, allowedExtension);
if (file.getSize() > MAX_FILE_SIZE) {
throw new IllegalArgumentException("文件过大");
}
if (this.fastUpload) {
String md5 = Md5Utils.getMd5(file);
String pathForMd5 = CacheUtils.get(CacheConstants.FILE_MD5_PATH_KEY, md5, String.class);
if (StringUtils.isNotEmpty(pathForMd5)) {
filePath = pathForMd5;
} else {
this.storageBucket.put(filePath, file);
CacheUtils.put(CacheConstants.FILE_MD5_PATH_KEY, md5, filePath);
CacheUtils.put(CacheConstants.FILE_PATH_MD5_KEY, filePath, md5);
}
} else {
this.storageBucket.put(filePath, file);
}
return generateUrl(filePath);
}
// 更多业务逻辑...
}
典型应用案例
场景1:简易文件操作(单服务单存储桶)
// 上传操作
String url = FileOperateUtils.upload("images/logo.png", new File("logo.png"));
// 下载操作
FileOperateUtils.download("images/logo.png", response);
// 获取文件URL
String previewUrl = FileOperateUtils.getUrl("images/logo.png");
场景2:多存储服务操作
// 多服务初始化
StorageBucket ossBucket = StorageUtils.getStorageBucket("OSS", "default");
StorageService ossService = new StorageService(ossBucket);
// 业务操作
String ossUrl = ossService.upload("videos/demo.mp4", videoFile);
场景3:分片上传实现
// 初始化分片上传
String uploadId = storageService.initMultipartUpload("large_file.zip", 1024*1024*100);
// 分片上传(10个分片)
List<String> etags = new ArrayList<>();
for (int i=1; i<=10; i++) {
String etag = storageService.uploadPart("large_file.zip", uploadId,
i, 1024*1024, getPartStream(i));
etags.add(etag);
}
// 完成分片上传
storageService.completeMultipartUpload("large_file.zip", uploadId, etags);
系统优势总结
优势维度 | 实现方式 |
---|---|
多服务兼容 | 通过StorageUtils 动态加载存储服务实现类 |
配置灵活性 | 支持按存储类型+客户端名的组合方式创建桶 |
业务可扩展性 | 在StorageService 中集中实现业务增强逻辑 |
开发效率提升 | 提供FileOperateUtils 简化常用操作 |
总结
该设计通过桥接模式实现了存储服务与业务逻辑的优雅分离,既保持了系统的扩展性,又通过工具类封装提升了开发效率。对于需要支持多云存储、复杂文件管理的业务场景,该架构提供了良好的可维护性和可演进性。
📌 本文档完整代码详见若依Geek仓库