From 42970d91ebde56436586c99737aa141cc5a7f2af Mon Sep 17 00:00:00 2001 From: luoqiz Date: Sat, 8 Mar 2025 17:56:51 +0800 Subject: [PATCH] =?UTF-8?q?refactor(system/file):=20=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B7=AF=E5=BE=84=E5=92=8Cmd5=E5=80=BC=20(#1?= =?UTF-8?q?38)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/config/file/FileRecorderImpl.java | 28 ++++++++--- .../admin/system/enums/FileTypeEnum.java | 16 ++++-- .../admin/system/model/entity/FileDO.java | 50 ++++++++++++++++--- .../admin/system/model/query/FileQuery.java | 7 +++ .../admin/system/model/resp/FileResp.java | 36 +++++++++++++ .../system/service/impl/FileServiceImpl.java | 11 ++-- .../db/changelog/mysql/main_table.sql | 9 +++- .../db/changelog/postgresql/main_table.sql | 14 +++++- 8 files changed, 147 insertions(+), 24 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 bb15e3b6..8ce75daf 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 @@ -20,6 +20,7 @@ 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.json.JSONUtil; import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -60,19 +61,34 @@ public class FileRecorderImpl implements FileRecorder { fileInfo.setId(id.longValue() + ""); String originalFilename = EscapeUtil.unescape(fileInfo.getOriginalFilename()); file.setName(StrUtil.contains(originalFilename, StringConstants.DOT) - ? StrUtil.subBefore(originalFilename, StringConstants.DOT, true) - : originalFilename); + ? StrUtil.subBefore(originalFilename, StringConstants.DOT, true) + : originalFilename); file.setUrl(fileInfo.getUrl()); file.setSize(fileInfo.getSize()); file.setExtension(fileInfo.getExt()); file.setType(FileTypeEnum.getByExtension(file.getExtension())); file.setThumbnailUrl(fileInfo.getThUrl()); file.setThumbnailSize(fileInfo.getThSize()); - StorageDO storage = (StorageDO)fileInfo.getAttr().get(ClassUtil.getClassName(StorageDO.class, false)); + StorageDO storage = (StorageDO) fileInfo.getAttr().get(ClassUtil.getClassName(StorageDO.class, false)); file.setStorageId(storage.getId()); file.setCreateTime(DateUtil.toLocalDateTime(fileInfo.getCreateTime())); file.setUpdateUser(UserContextHolder.getUserId()); file.setUpdateTime(file.getCreateTime()); + String absPath = fileInfo.getPath(); + if (absPath.endsWith("/")) { + String tempAbsPath = absPath.substring(0, absPath.length() - 1); + String[] pathArr = tempAbsPath.split(StringConstants.SLASH); + if (pathArr.length > 1) { + file.setParentPath(pathArr[pathArr.length - 1]); + } else { + file.setParentPath(StringConstants.SLASH); + } + } + file.setMd5(fileInfo.getHashInfo().getMd5()); + file.setAbsPath(fileInfo.getPath()); + file.setMetadata(JSONUtil.toJsonStr(fileInfo.getMetadata())); + file.setThumbnailMetadata(JSONUtil.toJsonStr(fileInfo.getThMetadata())); + file.setContentType(fileInfo.getContentType()); fileMapper.insert(file); return true; } @@ -117,8 +133,8 @@ public class FileRecorderImpl implements FileRecorder { private FileDO getFileByUrl(String url) { Optional fileOptional = fileMapper.lambdaQuery().eq(FileDO::getUrl, url).oneOpt(); return fileOptional.orElseGet(() -> fileMapper.lambdaQuery() - .likeLeft(FileDO::getUrl, StrUtil.subAfter(url, StringConstants.SLASH, true)) - .oneOpt() - .orElse(null)); + .likeLeft(FileDO::getUrl, StrUtil.subAfter(url, StringConstants.SLASH, true)) + .oneOpt() + .orElse(null)); } } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/system/enums/FileTypeEnum.java b/continew-module-system/src/main/java/top/continew/admin/system/enums/FileTypeEnum.java index c0735ad0..0c08c0ec 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/enums/FileTypeEnum.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/enums/FileTypeEnum.java @@ -35,6 +35,11 @@ import java.util.List; @RequiredArgsConstructor public enum FileTypeEnum implements BaseEnum { + /** + * 目录 + */ + DIR(0, "目录", Collections.emptyList()), + /** * 其他 */ @@ -44,7 +49,7 @@ public enum FileTypeEnum implements BaseEnum { * 图片 */ IMAGE(2, "图片", List - .of("jpg", "jpeg", "png", "gif", "bmp", "webp", "ico", "psd", "tiff", "dwg", "jxr", "apng", "xcf")), + .of("jpg", "jpeg", "png", "gif", "bmp", "webp", "ico", "psd", "tiff", "dwg", "jxr", "apng", "xcf")), /** * 文档 @@ -59,7 +64,8 @@ public enum FileTypeEnum implements BaseEnum { /** * 音频 */ - AUDIO(5, "音频", List.of("mp3", "flac", "wav", "ogg", "midi", "m4a", "aac", "amr", "ac3", "aiff")),; + AUDIO(5, "音频", List.of("mp3", "flac", "wav", "ogg", "midi", "m4a", "aac", "amr", "ac3", "aiff")), + ; private final Integer value; private final String description; @@ -73,8 +79,8 @@ public enum FileTypeEnum implements BaseEnum { */ public static FileTypeEnum getByExtension(String extension) { return Arrays.stream(FileTypeEnum.values()) - .filter(t -> t.getExtensions().contains(StrUtil.emptyIfNull(extension).toLowerCase())) - .findFirst() - .orElse(FileTypeEnum.UNKNOWN); + .filter(t -> t.getExtensions().contains(StrUtil.emptyIfNull(extension).toLowerCase())) + .findFirst() + .orElse(FileTypeEnum.UNKNOWN); } } 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 95ce396a..5f388fa2 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 @@ -17,18 +17,20 @@ package top.continew.admin.system.model.entity; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.SneakyThrows; 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 top.continew.admin.common.model.entity.BaseDO; import java.io.Serial; import java.net.URL; +import java.util.Map; /** * 文件实体 @@ -58,6 +60,31 @@ public class FileDO extends BaseDO { */ private String url; + /** + * 上级目录 + */ + private String parentPath; + + /** + * 绝对路径 + */ + private String absPath; + + /** + * 文件元数据 + */ + private String metadata; + + /** + * 文件类型 + */ + private String contentType; + + /** + * 文件md5值 + */ + private String md5; + /** * 扩展名 */ @@ -78,6 +105,11 @@ public class FileDO extends BaseDO { */ private String thumbnailUrl; + /** + * 文件元数据 + */ + private String thumbnailMetadata; + /** * 存储 ID */ @@ -94,10 +126,10 @@ public class FileDO extends BaseDO { fileInfo.setUrl(this.url); fileInfo.setSize(this.size); fileInfo.setFilename(StrUtil.contains(this.url, StringConstants.SLASH) - ? StrUtil.subAfter(this.url, StringConstants.SLASH, true) - : this.url); + ? StrUtil.subAfter(this.url, StringConstants.SLASH, true) + : this.url); fileInfo.setOriginalFilename(StrUtils - .blankToDefault(this.extension, this.name, ex -> this.name + StringConstants.DOT + ex)); + .blankToDefault(this.extension, this.name, ex -> this.name + StringConstants.DOT + ex)); fileInfo.setBasePath(StringConstants.EMPTY); // 优化 path 处理 fileInfo.setPath(extractRelativePath(this.url, storageDO)); @@ -106,9 +138,15 @@ public class FileDO extends BaseDO { fileInfo.setPlatform(storageDO.getCode()); fileInfo.setThUrl(this.thumbnailUrl); fileInfo.setThFilename(StrUtil.contains(this.thumbnailUrl, StringConstants.SLASH) - ? StrUtil.subAfter(this.thumbnailUrl, StringConstants.SLASH, true) - : this.thumbnailUrl); + ? StrUtil.subAfter(this.thumbnailUrl, StringConstants.SLASH, true) + : this.thumbnailUrl); fileInfo.setThSize(this.thumbnailSize); + 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; } diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/query/FileQuery.java b/continew-module-system/src/main/java/top/continew/admin/system/model/query/FileQuery.java index 6580f0a5..6018229e 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/query/FileQuery.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/model/query/FileQuery.java @@ -45,6 +45,13 @@ public class FileQuery implements Serializable { @Query(type = QueryType.LIKE) private String name; + /** + * 绝对路径 + */ + @Schema(description = "绝对路径", example = "/2025") + @Query(type = QueryType.EQ) + private String absPath; + /** * 类型 */ diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/FileResp.java b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/FileResp.java index 381f729d..e2888c29 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/FileResp.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/FileResp.java @@ -56,6 +56,36 @@ public class FileResp extends BaseDetailResp { @Schema(description = "URL", example = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/example/example.jpg") private String url; + /** + * 上级目录 + */ + @Schema(description = "上级目录", example = "25") + private String parentPath; + + /** + * 绝对路径 + */ + @Schema(description = "绝对路径", example = "/2025/2/25") + private String absPath; + + /** + * 文件元数据 + */ + @Schema(description = "文件元数据", example = "{width:1024,height:1024}") + private String metadata; + + /** + * 文件md5值 + */ + @Schema(description = "文件md5值", example = "abcdefghijklmnopqrstuvwxyz0123456789") + private String md5; + + /** + * 文件类型 + */ + @Schema(description = "文件md5值", example = "abcdefghijklmnopqrstuvwxyz0123456789") + private String contentType; + /** * 扩展名 */ @@ -80,6 +110,12 @@ public class FileResp extends BaseDetailResp { @Schema(description = "缩略图 URL", example = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/example/example.jpg.min.jpg") private String thumbnailUrl; + /** + * 缩略图文件元数据 + */ + @Schema(description = "缩略图文件元数据", example = "{width:100,height:100}") + private String thumbnailMetadata; + /** * 存储 ID */ diff --git a/continew-module-system/src/main/java/top/continew/admin/system/service/impl/FileServiceImpl.java b/continew-module-system/src/main/java/top/continew/admin/system/service/impl/FileServiceImpl.java index e8f18305..54978b47 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/service/impl/FileServiceImpl.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/service/impl/FileServiceImpl.java @@ -91,11 +91,12 @@ public class FileServiceImpl extends BaseServiceImpl img.size(100, 100)); @@ -154,7 +155,7 @@ public class FileServiceImpl extends BaseServiceImpl URLUtil - .normalize(prefix + thUrl)); + .normalize(prefix + thUrl)); fileResp.setThumbnailUrl(thumbnailUrl); fileResp.setStorageName("%s (%s)".formatted(storage.getName(), storage.getCode())); } diff --git a/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql b/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql index bfdd19e1..2aef0ab6 100644 --- a/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql +++ b/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql @@ -281,10 +281,16 @@ CREATE TABLE IF NOT EXISTS `sys_file` ( `name` varchar(255) NOT NULL COMMENT '名称', `size` bigint(20) NOT NULL COMMENT '大小(字节)', `url` varchar(512) NOT NULL COMMENT 'URL', + `parent_path` varchar(512) NOT NULL COMMENT '上级目录', + `abs_path` varchar(1024) NOT NULL COMMENT '绝对路径', `extension` varchar(100) DEFAULT NULL COMMENT '扩展名', + `metadata` TEXT NOT NULL COMMENT '元数据', + `content_type` varchar(64) NOT NULL COMMENT '文件类型', + `md5` varchar(128) NOT NULL COMMENT '文件md5值', `thumbnail_size` bigint(20) DEFAULT NULL COMMENT '缩略图大小(字节)', `thumbnail_url` varchar(512) DEFAULT NULL COMMENT '缩略图URL', - `type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型(1:其他;2:图片;3:文档;4:视频;5:音频)', + `thumbnail_metadata` TEXT COMMENT '元数据', + `type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型(0: 目录;1:其他;2:图片;3:文档;4:视频;5:音频)', `storage_id` bigint(20) NOT NULL COMMENT '存储ID', `create_user` bigint(20) NOT NULL COMMENT '创建人', `create_time` datetime NOT NULL COMMENT '创建时间', @@ -293,6 +299,7 @@ CREATE TABLE IF NOT EXISTS `sys_file` ( PRIMARY KEY (`id`), INDEX `idx_url`(`url`), INDEX `idx_type`(`type`), + INDEX `idx_sys_file_md5`(`md5`), INDEX `idx_create_user`(`create_user`), INDEX `idx_update_user`(`update_user`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件表'; diff --git a/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql b/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql index 047dc9b1..5da435cc 100644 --- a/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql +++ b/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql @@ -467,9 +467,15 @@ CREATE TABLE IF NOT EXISTS "sys_file" ( "name" varchar(255) NOT NULL, "size" int8 NOT NULL, "url" varchar(512) NOT NULL, + "parent_path" varchar(512) NOT NULL default '/', + "abs_path" varchar(512) NOT NULL, "extension" varchar(100) DEFAULT NULL, + "metadata" varchar(10000) NOT NULL DEFAULT '', + "content_type" varchar(64) NOT NULL, + "md5" varchar(128) NOT NULL DEFAULT '', "thumbnail_size" int8 DEFAULT NULL, "thumbnail_url" varchar(512) DEFAULT NULL, + "thumbnail_metadata" varchar(10000) DEFAULT NULL, "type" int2 NOT NULL DEFAULT 1, "storage_id" int8 NOT NULL, "create_user" int8 NOT NULL, @@ -482,14 +488,20 @@ CREATE INDEX "idx_file_url" ON "sys_file" ("url"); CREATE INDEX "idx_file_type" ON "sys_file" ("type"); CREATE INDEX "idx_file_create_user" ON "sys_file" ("create_user"); CREATE INDEX "idx_file_update_user" ON "sys_file" ("update_user"); +CREATE INDEX "idx_sys_file_md5" ON "sys_file" ("md5"); COMMENT ON COLUMN "sys_file"."id" IS 'ID'; COMMENT ON COLUMN "sys_file"."name" IS '名称'; COMMENT ON COLUMN "sys_file"."size" IS '大小(字节)'; COMMENT ON COLUMN "sys_file"."url" IS 'URL'; +COMMENT ON COLUMN "sys_file"."parent_path" IS '上级目录'; +COMMENT ON COLUMN "sys_file"."abs_path" IS '绝对路径'; COMMENT ON COLUMN "sys_file"."extension" IS '扩展名'; COMMENT ON COLUMN "sys_file"."thumbnail_size" IS '缩略图大小(字节)'; COMMENT ON COLUMN "sys_file"."thumbnail_url" IS '缩略图URL'; -COMMENT ON COLUMN "sys_file"."type" IS '类型(1:其他;2:图片;3:文档;4:视频;5:音频)'; +COMMENT ON COLUMN "sys_file"."type" IS '类型(0: 目录;1:其他;2:图片;3:文档;4:视频;5:音频)'; +COMMENT ON COLUMN "sys_file"."metadata" IS '元数据'; +COMMENT ON COLUMN "sys_file"."content_type" IS '文件类型'; +COMMENT ON COLUMN "sys_file"."md5" IS '文件md5值'; COMMENT ON COLUMN "sys_file"."storage_id" IS '存储ID'; COMMENT ON COLUMN "sys_file"."create_user" IS '创建人'; COMMENT ON COLUMN "sys_file"."create_time" IS '创建时间';