From bc057da265fdafe1ca91cf6206f0da6f676db58d Mon Sep 17 00:00:00 2001
From: Charles7c
Date: Wed, 14 May 2025 23:01:08 +0800
Subject: [PATCH] =?UTF-8?q?refactor(system):=20=E9=87=8D=E6=9E=84=E5=AD=98?=
=?UTF-8?q?=E5=82=A8=E9=85=8D=E7=BD=AE=E5=8F=8A=E6=96=87=E4=BB=B6=E4=B8=8A?=
=?UTF-8?q?=E4=BC=A0=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
存储配置自动处理:domain 不能以 / 结尾,bucket 必须以 / 结尾
文件上传:path 自动处理
Closes #IC6V43
---
.../system/config/file/FileRecorderImpl.java | 60 ++----
.../config/file/FileStorageConfigLoader.java | 4 +-
.../admin/system/enums/StorageTypeEnum.java | 45 ++++-
.../admin/system/model/entity/FileDO.java | 90 ++++-----
.../admin/system/service/FileService.java | 36 ++--
.../admin/system/service/StorageService.java | 18 +-
.../system/service/impl/FileServiceImpl.java | 42 ++--
.../service/impl/StorageServiceImpl.java | 179 ++++++++++--------
.../controller/common/CommonController.java | 6 +-
9 files changed, 261 insertions(+), 219 deletions(-)
diff --git a/continew-module-system/src/main/java/top/continew/admin/system/config/file/FileRecorderImpl.java b/continew-module-system/src/main/java/top/continew/admin/system/config/file/FileRecorderImpl.java
index 18c97130..4dc429be 100644
--- a/continew-module-system/src/main/java/top/continew/admin/system/config/file/FileRecorderImpl.java
+++ b/continew-module-system/src/main/java/top/continew/admin/system/config/file/FileRecorderImpl.java
@@ -16,26 +16,21 @@
package top.continew.admin.system.config.file;
-import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ClassUtil;
-import cn.hutool.core.util.EscapeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
-import cn.hutool.json.JSONUtil;
-import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.recorder.FileRecorder;
import org.dromara.x.file.storage.core.upload.FilePartInfo;
import org.springframework.stereotype.Component;
-import top.continew.admin.common.context.UserContextHolder;
-import top.continew.admin.system.enums.FileTypeEnum;
import top.continew.admin.system.mapper.FileMapper;
import top.continew.admin.system.mapper.StorageMapper;
import top.continew.admin.system.model.entity.FileDO;
import top.continew.admin.system.model.entity.StorageDO;
import top.continew.starter.core.constant.StringConstants;
+import top.continew.starter.core.util.URLUtils;
import java.util.Optional;
@@ -52,53 +47,24 @@ public class FileRecorderImpl implements FileRecorder {
private final FileMapper fileMapper;
private final StorageMapper storageMapper;
- private final IdentifierGenerator identifierGenerator;
- /**
- * 文件信息存储
- *
- * @param fileInfo 文件信息对象
- * @return 是否保存成功
- */
@Override
public boolean save(FileInfo fileInfo) {
- FileDO file = new FileDO();
- Number id = identifierGenerator.nextId(fileInfo);
- file.setId(id.longValue());
- fileInfo.setId(String.valueOf(id.longValue()));
- String originalFilename = EscapeUtil.unescape(fileInfo.getOriginalFilename());
- file.setName(StrUtil.contains(originalFilename, StringConstants.DOT)
- ? StrUtil.subBefore(originalFilename, StringConstants.DOT, true)
- : originalFilename);
+ // 保存文件信息
+ FileDO file = new FileDO(fileInfo);
StorageDO storage = (StorageDO)fileInfo.getAttr().get(ClassUtil.getClassName(StorageDO.class, false));
- String filePath = StrUtil.appendIfMissing(fileInfo.getPath(), StringConstants.SLASH);
- // 处理fileInfo中存储的地址
- fileInfo.setUrl(URLUtil.normalize(storage.getDomain() + filePath + fileInfo.getFilename()));
- fileInfo.setThUrl(URLUtil.normalize(storage.getDomain() + filePath + fileInfo.getThFilename()));
- file.setUrl(fileInfo.getUrl());
- file.setSize(fileInfo.getSize());
- String absPath = fileInfo.getPath();
- String tempAbsPath = absPath.length() > 1 ? StrUtil.removeSuffix(absPath, StringConstants.SLASH) : absPath;
- String[] pathArr = tempAbsPath.split(StringConstants.SLASH);
- if (pathArr.length > 1) {
- file.setParentPath(pathArr[pathArr.length - 1]);
- } else {
- file.setParentPath(StringConstants.SLASH);
- }
- file.setAbsPath(tempAbsPath);
- file.setExtension(fileInfo.getExt());
- file.setType(FileTypeEnum.getByExtension(file.getExtension()));
- file.setContentType(fileInfo.getContentType());
- file.setSha256(fileInfo.getHashInfo().getSha256());
- file.setMetadata(JSONUtil.toJsonStr(fileInfo.getMetadata()));
- file.setThumbnailUrl(fileInfo.getThUrl());
- file.setThumbnailSize(fileInfo.getThSize());
- file.setThumbnailMetadata(JSONUtil.toJsonStr(fileInfo.getThMetadata()));
file.setStorageId(storage.getId());
- file.setCreateTime(DateUtil.toLocalDateTime(fileInfo.getCreateTime()));
- file.setUpdateUser(UserContextHolder.getUserId());
- file.setUpdateTime(file.getCreateTime());
fileMapper.insert(file);
+ // 方便文件上传完成后获取文件信息
+ fileInfo.setId(String.valueOf(file.getId()));
+ if (!URLUtils.isHttpUrl(fileInfo.getUrl())) {
+ String prefix = StrUtil.appendIfMissing(storage.getDomain(), StringConstants.SLASH);
+ String url = URLUtil.normalize(prefix + fileInfo.getUrl());
+ fileInfo.setUrl(url);
+ if (StrUtil.isNotBlank(fileInfo.getThUrl())) {
+ fileInfo.setThUrl(URLUtil.normalize(prefix + fileInfo.getThUrl()));
+ }
+ }
return true;
}
diff --git a/continew-module-system/src/main/java/top/continew/admin/system/config/file/FileStorageConfigLoader.java b/continew-module-system/src/main/java/top/continew/admin/system/config/file/FileStorageConfigLoader.java
index 6e0d5b4e..8e3e26b0 100644
--- a/continew-module-system/src/main/java/top/continew/admin/system/config/file/FileStorageConfigLoader.java
+++ b/continew-module-system/src/main/java/top/continew/admin/system/config/file/FileStorageConfigLoader.java
@@ -24,8 +24,8 @@ import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import top.continew.admin.common.enums.DisEnableStatusEnum;
+import top.continew.admin.system.model.entity.StorageDO;
import top.continew.admin.system.model.query.StorageQuery;
-import top.continew.admin.system.model.req.StorageReq;
import top.continew.admin.system.model.resp.StorageResp;
import top.continew.admin.system.service.StorageService;
@@ -52,6 +52,6 @@ public class FileStorageConfigLoader implements ApplicationRunner {
if (CollUtil.isEmpty(storageList)) {
return;
}
- storageList.forEach(s -> storageService.load(BeanUtil.copyProperties(s, StorageReq.class)));
+ storageList.forEach(storage -> storageService.load(BeanUtil.copyProperties(storage, StorageDO.class)));
}
}
diff --git a/continew-module-system/src/main/java/top/continew/admin/system/enums/StorageTypeEnum.java b/continew-module-system/src/main/java/top/continew/admin/system/enums/StorageTypeEnum.java
index 54868f5e..54981411 100644
--- a/continew-module-system/src/main/java/top/continew/admin/system/enums/StorageTypeEnum.java
+++ b/continew-module-system/src/main/java/top/continew/admin/system/enums/StorageTypeEnum.java
@@ -16,9 +16,15 @@
package top.continew.admin.system.enums;
+import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import top.continew.admin.system.model.req.StorageReq;
+import top.continew.admin.system.validation.ValidationGroup;
+import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.enums.BaseEnum;
+import top.continew.starter.core.util.URLUtils;
+import top.continew.starter.core.validation.ValidationUtils;
/**
* 存储类型枚举
@@ -33,13 +39,48 @@ public enum StorageTypeEnum implements BaseEnum {
/**
* 本地存储
*/
- LOCAL(1, "本地存储"),
+ LOCAL(1, "本地存储") {
+ @Override
+ public void validate(StorageReq req) {
+ ValidationUtils.validate(req, ValidationGroup.Storage.Local.class);
+ ValidationUtils.throwIf(!URLUtils.isHttpUrl(req.getDomain()), "访问路径格式不正确");
+ }
+
+ @Override
+ public void pretreatment(StorageReq req) {
+ super.pretreatment(req);
+ req.setBucketName(StrUtil.appendIfMissing(req.getBucketName()
+ .replace(StringConstants.BACKSLASH, StringConstants.SLASH), StringConstants.SLASH));
+ }
+ },
/**
* 对象存储
*/
- OSS(2, "对象存储");
+ OSS(2, "对象存储") {
+ @Override
+ public void validate(StorageReq req) {
+ ValidationUtils.validate(req, ValidationGroup.Storage.OSS.class);
+ ValidationUtils.throwIf(!URLUtils.isHttpUrl(req.getDomain()), "域名格式不正确");
+ }
+ };
private final Integer value;
private final String description;
+
+ /**
+ * 校验
+ *
+ * @param req 请求参数
+ */
+ public abstract void validate(StorageReq req);
+
+ /**
+ * 处理参数
+ *
+ * @param req 请求参数
+ */
+ public void pretreatment(StorageReq req) {
+ req.setDomain(StrUtil.removeSuffix(req.getDomain(), StringConstants.SLASH));
+ }
}
diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/entity/FileDO.java b/continew-module-system/src/main/java/top/continew/admin/system/model/entity/FileDO.java
index 2af3d336..6578b8d9 100644
--- a/continew-module-system/src/main/java/top/continew/admin/system/model/entity/FileDO.java
+++ b/continew-module-system/src/main/java/top/continew/admin/system/model/entity/FileDO.java
@@ -16,20 +16,21 @@
package top.continew.admin.system.model.entity;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.file.FileNameUtil;
+import cn.hutool.core.util.EscapeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
-import lombok.SneakyThrows;
+import lombok.NoArgsConstructor;
import org.dromara.x.file.storage.core.FileInfo;
import top.continew.admin.common.model.entity.BaseDO;
import top.continew.admin.system.enums.FileTypeEnum;
-import top.continew.admin.system.enums.StorageTypeEnum;
import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.util.StrUtils;
import java.io.Serial;
-import java.net.URL;
import java.util.Map;
/**
@@ -39,6 +40,7 @@ import java.util.Map;
* @since 2023/12/23 10:38
*/
@Data
+@NoArgsConstructor
@TableName("sys_file")
public class FileDO extends BaseDO {
@@ -116,65 +118,63 @@ public class FileDO extends BaseDO {
private Long storageId;
/**
- * 转换为 X-File-Storage 文件信息对象
+ * 基于 {@link FileInfo} 构建文件信息对象
*
- * @param storageDO 存储桶信息
- * @return X-File-Storage 文件信息对象
+ * @param fileInfo {@link FileInfo} 文件信息
*/
- public FileInfo toFileInfo(StorageDO storageDO) {
+ public FileDO(FileInfo fileInfo) {
+ this.name = FileNameUtil.getPrefix(EscapeUtil.unescape(fileInfo.getOriginalFilename()));
+ this.size = fileInfo.getSize();
+ this.url = fileInfo.getUrl();
+ this.absPath = StrUtil.isEmpty(fileInfo.getPath())
+ ? StringConstants.SLASH
+ : StrUtil.prependIfMissing(fileInfo.getPath(), StringConstants.SLASH);
+ String[] pathAttr = this.absPath.split(StringConstants.SLASH);
+ this.parentPath = pathAttr.length > 1 ? pathAttr[pathAttr.length - 1] : StringConstants.SLASH;
+ this.extension = fileInfo.getExt();
+ this.contentType = fileInfo.getContentType();
+ this.type = FileTypeEnum.getByExtension(this.extension);
+ this.sha256 = fileInfo.getHashInfo().getSha256();
+ this.metadata = JSONUtil.toJsonStr(fileInfo.getMetadata());
+ this.thumbnailSize = fileInfo.getThSize();
+ this.thumbnailUrl = fileInfo.getThUrl();
+ this.thumbnailMetadata = JSONUtil.toJsonStr(fileInfo.getThMetadata());
+ this.setCreateTime(DateUtil.toLocalDateTime(fileInfo.getCreateTime()));
+ }
+
+ /**
+ * 转换为 {@link FileInfo} 文件信息对象
+ *
+ * @param storage 存储配置信息
+ * @return {@link FileInfo} 文件信息对象
+ */
+ public FileInfo toFileInfo(StorageDO storage) {
FileInfo fileInfo = new FileInfo();
- fileInfo.setUrl(this.url);
- fileInfo.setSize(this.size);
+ fileInfo.setPlatform(storage.getCode());
fileInfo.setFilename(StrUtil.contains(this.url, StringConstants.SLASH)
? StrUtil.subAfter(this.url, StringConstants.SLASH, true)
: this.url);
fileInfo.setOriginalFilename(StrUtils
.blankToDefault(this.extension, this.name, ex -> this.name + StringConstants.DOT + ex));
fileInfo.setBasePath(StringConstants.EMPTY);
- // 优化 path 处理
- fileInfo.setPath(extractRelativePath(this.url, storageDO));
-
+ fileInfo.setSize(this.size);
+ fileInfo.setUrl(this.url);
+ fileInfo.setPath(StringConstants.SLASH.equals(this.absPath)
+ ? StringConstants.EMPTY
+ : StrUtil.removePrefix(this.absPath, StringConstants.SLASH));
fileInfo.setExt(this.extension);
- fileInfo.setPlatform(storageDO.getCode());
- fileInfo.setThUrl(this.thumbnailUrl);
+ if (StrUtil.isNotBlank(this.metadata)) {
+ fileInfo.setMetadata(JSONUtil.toBean(this.metadata, Map.class));
+ }
+ // 缩略图信息
fileInfo.setThFilename(StrUtil.contains(this.thumbnailUrl, StringConstants.SLASH)
? StrUtil.subAfter(this.thumbnailUrl, StringConstants.SLASH, true)
: this.thumbnailUrl);
fileInfo.setThSize(this.thumbnailSize);
+ fileInfo.setThUrl(this.thumbnailUrl);
if (StrUtil.isNotBlank(this.thumbnailMetadata)) {
fileInfo.setThMetadata(JSONUtil.toBean(this.thumbnailMetadata, Map.class));
}
- if (StrUtil.isNotBlank(this.metadata)) {
- fileInfo.setMetadata(JSONUtil.toBean(this.metadata, Map.class));
- }
return fileInfo;
}
-
- /**
- * 将文件路径处理成资源路径
- * 例如:
- * http://domain.cn/bucketName/2024/11/27/6746ec3b2907f0de80afdd70.png => 2024/11/27/
- * http://bucketName.domain.cn/2024/11/27/6746ec3b2907f0de80afdd70.png => 2024/11/27/
- *
- * @param url 文件路径
- * @param storageDO 存储桶信息
- * @return
- */
- @SneakyThrows
- private static String extractRelativePath(String url, StorageDO storageDO) {
- url = StrUtil.subBefore(url, StringConstants.SLASH, true) + StringConstants.SLASH;
- if (storageDO.getType().equals(StorageTypeEnum.LOCAL)) {
- return url;
- }
- // 提取 URL 中的路径部分
- String fullPath = new URL(url).getPath();
- // 移除开头的斜杠
- String relativePath = fullPath.startsWith(StringConstants.SLASH) ? fullPath.substring(1) : fullPath;
- // 如果路径以 bucketName 开头,则移除 bucketName 例如: bucketName/2024/11/27/ -> 2024/11/27/
- if (relativePath.startsWith(storageDO.getBucketName())) {
- return StrUtil.subAfter(relativePath, storageDO.getBucketName(), false);
- }
- return relativePath;
- }
-
}
diff --git a/continew-module-system/src/main/java/top/continew/admin/system/service/FileService.java b/continew-module-system/src/main/java/top/continew/admin/system/service/FileService.java
index 34df8b61..192141b1 100644
--- a/continew-module-system/src/main/java/top/continew/admin/system/service/FileService.java
+++ b/continew-module-system/src/main/java/top/continew/admin/system/service/FileService.java
@@ -89,9 +89,29 @@ public interface FileService extends BaseService createDir(FileReq req);
+
/**
* 获取默认文件路径
*
+ *
+ * 默认文件路径:yyyy/MM/dd/
+ *
+ *
* @return 默认文件路径
*/
default String getDefaultFilePath() {
@@ -99,20 +119,4 @@ public interface FileService extends BaseService createDir(FileReq req);
}
\ No newline at end of file
diff --git a/continew-module-system/src/main/java/top/continew/admin/system/service/StorageService.java b/continew-module-system/src/main/java/top/continew/admin/system/service/StorageService.java
index 50eb35b0..940f9932 100644
--- a/continew-module-system/src/main/java/top/continew/admin/system/service/StorageService.java
+++ b/continew-module-system/src/main/java/top/continew/admin/system/service/StorageService.java
@@ -50,29 +50,29 @@ public interface StorageService extends BaseService ids) {
+ public void beforeDelete(List ids) {
List fileList = baseMapper.lambdaQuery().in(FileDO::getId, ids).list();
Map> fileListGroup = fileList.stream().collect(Collectors.groupingBy(FileDO::getStorageId));
for (Map.Entry> entry : fileListGroup.entrySet()) {
@@ -87,23 +88,17 @@ public class FileServiceImpl extends BaseServiceImpl allExtensions = FileTypeEnum.getAllExtensions();
CheckUtils.throwIf(!allExtensions.contains(extName), "不支持的文件类型,仅支持 {} 格式的文件", String
.join(StringConstants.CHINESE_COMMA, allExtensions));
- // 获取存储信息
- StorageDO storage;
- if (StrUtil.isBlank(storageCode)) {
- storage = storageService.getDefaultStorage();
- CheckUtils.throwIfNull(storage, "请先指定默认存储");
- } else {
- storage = storageService.getByCode(storageCode);
- CheckUtils.throwIfNotExists(storage, "StorageDO", "Code", storageCode);
- }
// 构建上传预处理对象
+ StorageDO storage = storageService.getByCode(storageCode);
+ CheckUtils.throwIf(DisEnableStatusEnum.DISABLE.equals(storage.getStatus()), "请先启用存储 [{}]", storage.getCode());
UploadPretreatment uploadPretreatment = fileStorageService.of(file)
.setPlatform(storage.getCode())
.setHashCalculatorSha256(true)
.putAttr(ClassUtil.getClassName(StorageDO.class, false), storage)
- .setPath(path);
+ .setPath(this.pretreatmentPath(path));
// 图片文件生成缩略图
if (FileTypeEnum.IMAGE.getExtensions().contains(extName)) {
+ uploadPretreatment.setIgnoreThumbnailException(true, true);
uploadPretreatment.thumbnail(img -> img.size(100, 100));
}
uploadPretreatment.setProgressMonitor(new ProgressListener() {
@@ -122,6 +117,7 @@ public class FileServiceImpl extends BaseServiceImpl
+ * 1.如果 path 为空,则使用 {@link FileService#getDefaultFilePath()} 作为默认值
+ * 2.如果 path 为 {@code /},则设置为空
+ * 3.如果 path 不以 {@code /} 结尾,则添加后缀 {@code /}
+ * 4.如果 path 以 {@code /} 开头,则移除前缀 {@code /}
+ * 示例:yyyy/MM/dd/
+ *
+ *
+ * @param path 路径
+ * @return 处理路径
+ */
+ private String pretreatmentPath(String path) {
+ if (StrUtil.isBlank(path)) {
+ return this.getDefaultFilePath();
+ }
+ if (StringConstants.SLASH.equals(path)) {
+ return StringConstants.EMPTY;
+ }
+ return StrUtil.appendIfMissing(StrUtil.removePrefix(path, StringConstants.SLASH), StringConstants.SLASH);
+ }
}
\ No newline at end of file
diff --git a/continew-module-system/src/main/java/top/continew/admin/system/service/impl/StorageServiceImpl.java b/continew-module-system/src/main/java/top/continew/admin/system/service/impl/StorageServiceImpl.java
index f87cc06f..88adf51f 100644
--- a/continew-module-system/src/main/java/top/continew/admin/system/service/impl/StorageServiceImpl.java
+++ b/continew-module-system/src/main/java/top/continew/admin/system/service/impl/StorageServiceImpl.java
@@ -16,7 +16,6 @@
package top.continew.admin.system.service.impl;
-import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
@@ -39,10 +38,8 @@ import top.continew.admin.system.model.req.StorageReq;
import top.continew.admin.system.model.resp.StorageResp;
import top.continew.admin.system.service.FileService;
import top.continew.admin.system.service.StorageService;
-import top.continew.admin.system.validation.ValidationGroup;
import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.util.ExceptionUtils;
-import top.continew.starter.core.util.URLUtils;
import top.continew.starter.core.validation.CheckUtils;
import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.extension.crud.service.BaseServiceImpl;
@@ -68,33 +65,55 @@ public class StorageServiceImpl extends BaseServiceImpl ids) {
CheckUtils.throwIf(fileService.countByStorageIds(ids) > 0, "所选存储存在文件关联,请删除文件后重试");
List storageList = baseMapper.lambdaQuery().in(StorageDO::getId, ids).list();
- storageList.forEach(s -> {
- CheckUtils.throwIfEqual(Boolean.TRUE, s.getIsDefault(), "[{}] 是默认存储,不允许删除", s.getName());
- // 卸载启用状态的存储
- if (DisEnableStatusEnum.ENABLE.equals(s.getStatus())) {
- this.unload(BeanUtil.copyProperties(s, StorageReq.class));
- }
+ storageList.forEach(storage -> {
+ CheckUtils.throwIfEqual(Boolean.TRUE, storage.getIsDefault(), "[{}] 是默认存储,不允许删除", storage.getName());
+ // 卸载存储引擎
+ this.unload(storage);
});
}
@@ -123,14 +140,13 @@ public class StorageServiceImpl extends BaseServiceImpl fileStorageList = fileStorageService.getFileStorageList();
- String domain = req.getDomain();
- ValidationUtils.throwIf(!URLUtils.isHttpUrl(domain), "域名格式不正确");
- String bucketName = req.getBucketName();
- StorageTypeEnum type = req.getType();
- if (StorageTypeEnum.LOCAL.equals(type)) {
- ValidationUtils.validate(req, ValidationGroup.Storage.Local.class);
- req.setBucketName(StrUtil.appendIfMissing(bucketName
- .replace(StringConstants.BACKSLASH, StringConstants.SLASH), StringConstants.SLASH));
- FileStorageProperties.LocalPlusConfig config = new FileStorageProperties.LocalPlusConfig();
- config.setPlatform(req.getCode());
- config.setStoragePath(bucketName);
- fileStorageList.addAll(FileStorageServiceBuilder.buildLocalPlusFileStorage(Collections
- .singletonList(config)));
- SpringWebUtils.registerResourceHandler(MapUtil.of(URLUtil.url(req.getDomain()).getPath(), bucketName));
- } else if (StorageTypeEnum.OSS.equals(type)) {
- ValidationUtils.validate(req, ValidationGroup.Storage.OSS.class);
- FileStorageProperties.AmazonS3Config config = new FileStorageProperties.AmazonS3Config();
- config.setPlatform(req.getCode());
- config.setAccessKey(req.getAccessKey());
- config.setSecretKey(req.getSecretKey());
- config.setEndPoint(req.getEndpoint());
- config.setBucketName(bucketName);
- config.setDomain(domain);
- fileStorageList.addAll(FileStorageServiceBuilder.buildAmazonS3FileStorage(Collections
- .singletonList(config), null));
+ switch (storage.getType()) {
+ case LOCAL -> {
+ FileStorageProperties.LocalPlusConfig config = new FileStorageProperties.LocalPlusConfig();
+ config.setPlatform(storage.getCode());
+ config.setStoragePath(storage.getBucketName());
+ fileStorageList.addAll(FileStorageServiceBuilder.buildLocalPlusFileStorage(Collections
+ .singletonList(config)));
+ SpringWebUtils.registerResourceHandler(MapUtil.of(URLUtil.url(storage.getDomain()).getPath(), storage
+ .getBucketName()));
+ }
+ case OSS -> {
+ FileStorageProperties.AmazonS3Config config = new FileStorageProperties.AmazonS3Config();
+ config.setPlatform(storage.getCode());
+ config.setAccessKey(storage.getAccessKey());
+ config.setSecretKey(storage.getSecretKey());
+ config.setEndPoint(storage.getEndpoint());
+ config.setBucketName(storage.getBucketName());
+ config.setDomain(storage.getDomain());
+ fileStorageList.addAll(FileStorageServiceBuilder.buildAmazonS3FileStorage(Collections
+ .singletonList(config), null));
+ }
+ default -> throw new IllegalArgumentException("不支持的存储类型:%s".formatted(storage.getType()));
}
}
@Override
- public void unload(StorageReq req) {
+ public void unload(StorageDO storage) {
+ FileStorage fileStorage = fileStorageService.getFileStorage(storage.getCode());
+ if (fileStorage == null) {
+ return;
+ }
CopyOnWriteArrayList fileStorageList = fileStorageService.getFileStorageList();
- FileStorage fileStorage = fileStorageService.getFileStorage(req.getCode());
fileStorageList.remove(fileStorage);
fileStorage.close();
- SpringWebUtils.deRegisterResourceHandler(MapUtil.of(URLUtil.url(req.getDomain()).getPath(), req
- .getBucketName()));
+ // 本地存储引擎需要移除资源映射
+ if (StorageTypeEnum.LOCAL.equals(storage.getType())) {
+ SpringWebUtils.deRegisterResourceHandler(MapUtil.of(URLUtil.url(storage.getDomain()).getPath(), storage
+ .getBucketName()));
+ }
}
/**
* 解密 SecretKey
*
- * @param req 请求参数
- * @param storage 存储信息
+ * @param encryptSecretKey 加密的 SecretKey
+ * @param storage 存储信息
+ * @return 解密后的 SecretKey
*/
- private void decodeSecretKey(StorageReq req, StorageDO storage) {
- if (!StorageTypeEnum.OSS.equals(req.getType())) {
- return;
- }
+ private String decryptSecretKey(String encryptSecretKey, StorageDO storage) {
// 修改时,如果 SecretKey 不修改,需要手动修正
- String newSecretKey = req.getSecretKey();
- boolean isSecretKeyNotUpdate = StrUtil.isBlank(newSecretKey) || newSecretKey.contains(StringConstants.ASTERISK);
- if (null != storage && isSecretKeyNotUpdate) {
- req.setSecretKey(storage.getSecretKey());
- return;
+ if (null != storage) {
+ boolean isSecretKeyNotUpdate = StrUtil.isBlank(encryptSecretKey) || encryptSecretKey
+ .contains(StringConstants.ASTERISK);
+ if (isSecretKeyNotUpdate) {
+ return storage.getSecretKey();
+ }
}
- // 新增时或修改了 SecretKey
- String secretKey = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(newSecretKey));
+ // 新增场景,直接解密 SecretKey
+ String secretKey = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(encryptSecretKey));
ValidationUtils.throwIfNull(secretKey, "私有密钥解密失败");
ValidationUtils.throwIf(secretKey.length() > 255, "私有密钥长度不能超过 255 个字符");
- req.setSecretKey(secretKey);
- }
-
- /**
- * 默认存储是否存在
- *
- * @param id ID
- * @return 是否存在
- */
- private boolean isDefaultExists(Long id) {
- return baseMapper.lambdaQuery().eq(StorageDO::getIsDefault, true).ne(null != id, StorageDO::getId, id).exists();
+ return secretKey;
}
/**
diff --git a/continew-webapi/src/main/java/top/continew/admin/controller/common/CommonController.java b/continew-webapi/src/main/java/top/continew/admin/controller/common/CommonController.java
index 39879641..4d1be6cd 100644
--- a/continew-webapi/src/main/java/top/continew/admin/controller/common/CommonController.java
+++ b/continew-webapi/src/main/java/top/continew/admin/controller/common/CommonController.java
@@ -35,8 +35,6 @@ import top.continew.admin.system.enums.OptionCategoryEnum;
import top.continew.admin.system.model.query.*;
import top.continew.admin.system.model.resp.file.FileUploadResp;
import top.continew.admin.system.service.*;
-import top.continew.starter.core.constant.StringConstants;
-import top.continew.starter.core.util.StrUtils;
import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.extension.crud.model.query.SortQuery;
import top.continew.starter.extension.crud.model.resp.LabelValueResp;
@@ -71,9 +69,7 @@ public class CommonController {
@PostMapping("/file")
public FileUploadResp upload(@NotNull(message = "文件不能为空") MultipartFile file, String path) throws IOException {
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
- String fixedPath = StrUtils.blankToDefault(path, StringConstants.SLASH, p -> StrUtil
- .appendIfMissing(p, StringConstants.SLASH));
- FileInfo fileInfo = fileService.upload(file, fixedPath);
+ FileInfo fileInfo = fileService.upload(file, path);
return FileUploadResp.builder()
.id(fileInfo.getId())
.url(fileInfo.getUrl())