feat(file、requirement): 优化文件服务和需求管理功能
- 新增按配置ID和路径获取文件的方法 - 实现文件不存在时的404响应处理 - 优化文件上传路径生成逻辑,使用UUID确保文件名安全性 - 添加需求执行选项查询接口和实现 - 支持排除特定状态码的需求分页查询 - 重构需求模块过滤逻辑并提取公共方法 - 修复S3客户端对象键解析问题
This commit is contained in:
@@ -131,6 +131,13 @@ public class FileController {
|
||||
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1432/
|
||||
path = URLUtil.decode(path, StandardCharsets.UTF_8, false);
|
||||
|
||||
FileDO file = fileService.getFileByConfigIdAndPath(configId, path);
|
||||
if (file == null) {
|
||||
log.warn("[getFileContent][configId({}) path({}) 文件不存在]", configId, path);
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取内容
|
||||
byte[] content = fileService.getFileContent(configId, path);
|
||||
if (content == null) {
|
||||
@@ -138,7 +145,7 @@ public class FileController {
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return;
|
||||
}
|
||||
writeAttachment(response, path, content);
|
||||
writeAttachment(response, StrUtil.blankToDefault(file.getName(), file.getPath()), content);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
|
||||
@@ -136,11 +136,11 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
|
||||
}
|
||||
|
||||
private String resolveObjectKey(String urlOrPath) {
|
||||
String cleaned = HttpUtils.removeUrlQuery(urlOrPath);
|
||||
if (!HttpUtil.isHttp(cleaned) && !HttpUtil.isHttps(cleaned)) {
|
||||
return cleaned;
|
||||
if (!HttpUtil.isHttp(urlOrPath) && !HttpUtil.isHttps(urlOrPath)) {
|
||||
return urlOrPath;
|
||||
}
|
||||
|
||||
String cleaned = HttpUtils.removeUrlQuery(urlOrPath);
|
||||
String path = StrUtil.removePrefix(cleaned, config.getDomain() + "/");
|
||||
if (StrUtil.equals(path, cleaned)) {
|
||||
URI uri = URI.create(cleaned);
|
||||
|
||||
@@ -63,6 +63,15 @@ public interface FileService {
|
||||
Long createFile(FileCreateReqVO createReqVO);
|
||||
FileDO getFile(Long id);
|
||||
|
||||
/**
|
||||
* 按 (configId, path) 获取文件记录。
|
||||
*
|
||||
* @param configId 文件配置编号
|
||||
* @param path 文件存储路径
|
||||
* @return 文件记录,不存在返回 null
|
||||
*/
|
||||
FileDO getFileByConfigIdAndPath(Long configId, String path);
|
||||
|
||||
/**
|
||||
* 通过文件 URL 获得文件。
|
||||
*
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.njcn.rdms.module.system.service.file;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -42,14 +43,6 @@ public class FileServiceImpl implements FileService {
|
||||
* 目的:按照日期,进行分目录
|
||||
*/
|
||||
static boolean PATH_PREFIX_DATE_ENABLE = true;
|
||||
/**
|
||||
* 上传文件的后缀,是否包含时间戳
|
||||
* <p>
|
||||
* 目的:保证文件的唯一性,避免覆盖
|
||||
* 定制:可按需调整成 UUID、或者其他方式
|
||||
*/
|
||||
static boolean PATH_SUFFIX_TIMESTAMP_ENABLE = true;
|
||||
|
||||
@Resource
|
||||
private FileConfigService fileConfigService;
|
||||
|
||||
@@ -103,34 +96,27 @@ public class FileServiceImpl implements FileService {
|
||||
|
||||
@VisibleForTesting
|
||||
String generateUploadPath(String name, String directory) {
|
||||
// 1. 生成前缀、后缀
|
||||
// 1. 生成前缀,并将存储文件名切换为安全 key:
|
||||
// path 仅承担对象存储 key / 路径职责,不再复用原文件名,避免 %、&、中文等字符进入 URI 路径。
|
||||
String prefix = null;
|
||||
if (PATH_PREFIX_DATE_ENABLE) {
|
||||
prefix = LocalDateTimeUtil.format(LocalDateTimeUtil.now(), PURE_DATE_PATTERN);
|
||||
}
|
||||
String suffix = null;
|
||||
if (PATH_SUFFIX_TIMESTAMP_ENABLE) {
|
||||
suffix = String.valueOf(System.currentTimeMillis());
|
||||
String ext = FileUtil.extName(name);
|
||||
String storageName = IdUtil.fastSimpleUUID();
|
||||
if (StrUtil.isNotEmpty(ext)) {
|
||||
storageName = storageName + StrUtil.DOT + ext;
|
||||
}
|
||||
|
||||
// 2.1 先拼接 suffix 后缀
|
||||
if (StrUtil.isNotEmpty(suffix)) {
|
||||
String ext = FileUtil.extName(name);
|
||||
if (StrUtil.isNotEmpty(ext)) {
|
||||
name = FileUtil.mainName(name) + StrUtil.C_UNDERLINE + suffix + StrUtil.DOT + ext;
|
||||
} else {
|
||||
name = name + StrUtil.C_UNDERLINE + suffix;
|
||||
}
|
||||
}
|
||||
// 2.2 再拼接 prefix 前缀
|
||||
// 2. 先拼接 prefix 前缀
|
||||
if (StrUtil.isNotEmpty(prefix)) {
|
||||
name = prefix + StrUtil.SLASH + name;
|
||||
storageName = prefix + StrUtil.SLASH + storageName;
|
||||
}
|
||||
// 2.3 最后拼接 directory 目录
|
||||
// 3. 最后拼接 directory 目录
|
||||
if (StrUtil.isNotEmpty(directory)) {
|
||||
name = directory + StrUtil.SLASH + name;
|
||||
storageName = directory + StrUtil.SLASH + storageName;
|
||||
}
|
||||
return name;
|
||||
return storageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -166,6 +152,14 @@ public class FileServiceImpl implements FileService {
|
||||
return validateFileExists(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileDO getFileByConfigIdAndPath(Long configId, String path) {
|
||||
if (configId == null || StrUtil.isBlank(path)) {
|
||||
return null;
|
||||
}
|
||||
return fileMapper.selectByConfigIdAndPath(configId, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileDO getFileByUrl(String url) {
|
||||
if (StrUtil.isBlank(url)) {
|
||||
|
||||
Reference in New Issue
Block a user