feat(system/file): 文件管理呈目录形式展示 (#151)

This commit is contained in:
luoqiz
2025-04-16 11:25:31 +08:00
committed by GitHub
parent be5bfc8a5b
commit 9b79990cc0
6 changed files with 82 additions and 18 deletions

View File

@@ -56,7 +56,7 @@ public class FileRecorderImpl implements FileRecorder {
/** /**
* 文件信息存储 * 文件信息存储
* *
* @param fileInfo 文件信息对象 * @param fileInfo 文件信息对象
* @return 是否保存成功 * @return 是否保存成功
*/ */
@@ -71,27 +71,25 @@ public class FileRecorderImpl implements FileRecorder {
? StrUtil.subBefore(originalFilename, StringConstants.DOT, true) ? StrUtil.subBefore(originalFilename, StringConstants.DOT, true)
: originalFilename); : originalFilename);
StorageDO storage = (StorageDO)fileInfo.getAttr().get(ClassUtil.getClassName(StorageDO.class, false)); StorageDO storage = (StorageDO)fileInfo.getAttr().get(ClassUtil.getClassName(StorageDO.class, false));
String domain = StrUtil.appendIfMissing(storage.getDomain(), StringConstants.SLASH); String filePath = StrUtil.appendIfMissing(fileInfo.getPath(), StringConstants.SLASH);
// 处理fileInfo中存储的地址 // 处理fileInfo中存储的地址
fileInfo.setUrl(URLUtil.normalize(domain + fileInfo.getPath() + fileInfo.getFilename())); fileInfo.setUrl(URLUtil.normalize(storage.getDomain() + filePath + fileInfo.getFilename()));
fileInfo.setThUrl(URLUtil.normalize(domain + fileInfo.getPath() + fileInfo.getThFilename())); fileInfo.setThUrl(URLUtil.normalize(storage.getDomain() + filePath + fileInfo.getThFilename()));
file.setUrl(fileInfo.getUrl()); file.setUrl(fileInfo.getUrl());
file.setSize(fileInfo.getSize()); file.setSize(fileInfo.getSize());
String absPath = fileInfo.getPath(); String absPath = fileInfo.getPath();
if (absPath.endsWith(StringConstants.SLASH)) { String tempAbsPath = absPath.length() > 1 ? StrUtil.removeSuffix(absPath, StringConstants.SLASH) : absPath;
String tempAbsPath = absPath.substring(0, absPath.length() - 1); String[] pathArr = tempAbsPath.split(StringConstants.SLASH);
String[] pathArr = tempAbsPath.split(StringConstants.SLASH); if (pathArr.length > 1) {
if (pathArr.length > 1) { file.setParentPath(pathArr[pathArr.length - 1]);
file.setParentPath(pathArr[pathArr.length - 1]); } else {
} else { file.setParentPath(StringConstants.SLASH);
file.setParentPath(StringConstants.SLASH);
}
} }
file.setAbsPath(fileInfo.getPath()); file.setAbsPath(tempAbsPath);
file.setExtension(fileInfo.getExt()); file.setExtension(fileInfo.getExt());
file.setType(FileTypeEnum.getByExtension(file.getExtension())); file.setType(FileTypeEnum.getByExtension(file.getExtension()));
file.setContentType(fileInfo.getContentType()); file.setContentType(fileInfo.getContentType());
file.setMd5(fileInfo.getHashInfo().getMd5()); file.setMd5(fileInfo.getHashInfo().getSha256());
file.setMetadata(JSONUtil.toJsonStr(fileInfo.getMetadata())); file.setMetadata(JSONUtil.toJsonStr(fileInfo.getMetadata()));
file.setThumbnailUrl(fileInfo.getThUrl()); file.setThumbnailUrl(fileInfo.getThUrl());
file.setThumbnailSize(fileInfo.getThSize()); file.setThumbnailSize(fileInfo.getThSize());

View File

@@ -44,4 +44,10 @@ public class FileReq implements Serializable {
@NotBlank(message = "文件名称不能为空") @NotBlank(message = "文件名称不能为空")
@Length(max = 255, message = "文件名称长度不能超过 {max} 个字符") @Length(max = 255, message = "文件名称长度不能超过 {max} 个字符")
private String name; private String name;
/**
* 上级目录
*/
@Schema(description = "上级目录", example = "25")
private String parentPath;
} }

View File

@@ -25,6 +25,7 @@ import top.continew.admin.system.model.resp.file.FileResp;
import top.continew.admin.system.model.resp.file.FileStatisticsResp; import top.continew.admin.system.model.resp.file.FileStatisticsResp;
import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.data.mp.service.IService; import top.continew.starter.data.mp.service.IService;
import top.continew.starter.extension.crud.model.resp.IdResp;
import top.continew.starter.extension.crud.service.BaseService; import top.continew.starter.extension.crud.service.BaseService;
import java.time.LocalDate; import java.time.LocalDate;
@@ -94,4 +95,8 @@ public interface FileService extends BaseService<FileResp, FileResp, FileQuery,
return today.getYear() + StringConstants.SLASH + today.getMonthValue() + StringConstants.SLASH + today return today.getYear() + StringConstants.SLASH + today.getMonthValue() + StringConstants.SLASH + today
.getDayOfMonth() + StringConstants.SLASH; .getDayOfMonth() + StringConstants.SLASH;
} }
FileResp check(String fileHash);
IdResp<Long> createDir(FileReq req);
} }

View File

@@ -44,6 +44,7 @@ import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.util.StrUtils; import top.continew.starter.core.util.StrUtils;
import top.continew.starter.core.util.URLUtils; import top.continew.starter.core.util.URLUtils;
import top.continew.starter.core.validation.CheckUtils; import top.continew.starter.core.validation.CheckUtils;
import top.continew.starter.extension.crud.model.resp.IdResp;
import top.continew.starter.extension.crud.service.BaseServiceImpl; import top.continew.starter.extension.crud.service.BaseServiceImpl;
import java.util.List; import java.util.List;
@@ -91,7 +92,9 @@ public class FileServiceImpl extends BaseServiceImpl<FileMapper, FileDO, FileRes
UploadPretreatment uploadPretreatment = fileStorageService.of(file) UploadPretreatment uploadPretreatment = fileStorageService.of(file)
.setPlatform(storage.getCode()) .setPlatform(storage.getCode())
.setHashCalculatorMd5(true) .setHashCalculatorMd5(true)
.setHashCalculatorSha256(true)
.putAttr(ClassUtil.getClassName(StorageDO.class, false), storage) .putAttr(ClassUtil.getClassName(StorageDO.class, false), storage)
// .setPath(StrUtil.removePrefix(path, StringConstants.SLASH));
.setPath(path); .setPath(path);
// 图片文件生成缩略图 // 图片文件生成缩略图
if (FileTypeEnum.IMAGE.getExtensions().contains(FileNameUtil.extName(file.getOriginalFilename()))) { if (FileTypeEnum.IMAGE.getExtensions().contains(FileNameUtil.extName(file.getOriginalFilename()))) {
@@ -138,6 +141,40 @@ public class FileServiceImpl extends BaseServiceImpl<FileMapper, FileDO, FileRes
return resp; return resp;
} }
@Override
public FileResp check(String fileHash) {
FileDO file = baseMapper.lambdaQuery().eq(FileDO::getMd5, fileHash).one();
if (file != null) {
return get(file.getId());
}
return null;
}
@Override
public IdResp<Long> createDir(FileReq req) {
StorageDO storage = storageService.getDefaultStorage();
FileDO fileDo = new FileDO();
fileDo.setName(req.getName());
fileDo.setSize(0L);
fileDo.setUrl(storage.getDomain() + req.getParentPath() + req.getName());
String absPath = req.getParentPath();
String tempAbsPath = absPath.length() > 1 ? StrUtil.removeSuffix(absPath, StringConstants.SLASH) : absPath;
String[] pathArr = tempAbsPath.split(StringConstants.SLASH);
if (pathArr.length > 1) {
fileDo.setParentPath(pathArr[pathArr.length - 1]);
} else {
fileDo.setParentPath(StringConstants.SLASH);
}
fileDo.setAbsPath(tempAbsPath);
fileDo.setExtension("dir");
fileDo.setContentType("");
fileDo.setType(FileTypeEnum.DIR);
fileDo.setMd5("");
fileDo.setStorageId(storage.getId());
baseMapper.insert(fileDo);
return new IdResp<>(fileDo.getId());
}
@Override @Override
protected void fill(Object obj) { protected void fill(Object obj) {
super.fill(obj); super.fill(obj);

View File

@@ -35,6 +35,7 @@ import top.continew.admin.system.enums.OptionCategoryEnum;
import top.continew.admin.system.model.query.*; import top.continew.admin.system.model.query.*;
import top.continew.admin.system.model.resp.file.FileUploadResp; import top.continew.admin.system.model.resp.file.FileUploadResp;
import top.continew.admin.system.service.*; import top.continew.admin.system.service.*;
import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.validation.ValidationUtils; import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.extension.crud.model.query.SortQuery; import top.continew.starter.extension.crud.model.query.SortQuery;
import top.continew.starter.extension.crud.model.resp.LabelValueResp; import top.continew.starter.extension.crud.model.resp.LabelValueResp;
@@ -66,9 +67,11 @@ public class CommonController {
@Operation(summary = "上传文件", description = "上传文件") @Operation(summary = "上传文件", description = "上传文件")
@PostMapping("/file") @PostMapping("/file")
public FileUploadResp upload(@NotNull(message = "文件不能为空") MultipartFile file) { public FileUploadResp upload(@NotNull(message = "文件不能为空") MultipartFile file, String path) {
ValidationUtils.throwIf(file::isEmpty, "文件不能为空"); ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
FileInfo fileInfo = fileService.upload(file); FileInfo fileInfo = fileService.upload(file, StrUtil.isNotBlank(path)
? StrUtil.appendIfMissing(path, StringConstants.SLASH)
: "/");
return FileUploadResp.builder() return FileUploadResp.builder()
.id(fileInfo.getId()) .id(fileInfo.getId())
.url(fileInfo.getUrl()) .url(fileInfo.getUrl())

View File

@@ -20,8 +20,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController; import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.FileQuery; import top.continew.admin.system.model.query.FileQuery;
import top.continew.admin.system.model.req.FileReq; import top.continew.admin.system.model.req.FileReq;
@@ -30,6 +29,7 @@ import top.continew.admin.system.model.resp.file.FileStatisticsResp;
import top.continew.admin.system.service.FileService; import top.continew.admin.system.service.FileService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping; import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api; import top.continew.starter.extension.crud.enums.Api;
import top.continew.starter.extension.crud.model.resp.IdResp;
import top.continew.starter.log.annotation.Log; import top.continew.starter.log.annotation.Log;
/** /**
@@ -51,4 +51,19 @@ public class FileController extends BaseController<FileService, FileResp, FileRe
public FileStatisticsResp statistics() { public FileStatisticsResp statistics() {
return baseService.statistics(); return baseService.statistics();
} }
@Log(ignore = true)
@Operation(summary = "检测文件是否存在", description = "检测文件是否存在")
@SaCheckPermission("system:file:check")
@GetMapping("/check")
public FileResp checkFile(String fileHash) {
return baseService.check(fileHash);
}
@Operation(summary = "创建文件夹", description = "创建文件夹")
@ResponseBody
@PostMapping("/createDir")
public IdResp<Long> createDir(@RequestBody FileReq req) {
return baseService.createDir(req);
}
} }