Commit 1c75665ae76d4a202914e4563841433f1209fd18

Authored by YunaiV
1 parent 60f13815

✨ feat(file): update file naming strategy to support timestamp as directory or suffix

yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java
@@ -47,7 +47,14 @@ public class FileServiceImpl implements FileService { @@ -47,7 +47,14 @@ public class FileServiceImpl implements FileService {
47 * 目的:保证文件的唯一性,避免覆盖 47 * 目的:保证文件的唯一性,避免覆盖
48 * 定制:可按需调整成 UUID、或者其他方式 48 * 定制:可按需调整成 UUID、或者其他方式
49 */ 49 */
50 - static boolean PATH_SUFFIX_TIMESTAMP_ENABLE = true; 50 + static boolean PATH_SUFFIX_TIMESTAMP_ENABLE = false;
  51 + /**
  52 + * 时间戳是否作为上级目录
  53 + *
  54 + * true:{@code yyyyMMdd/timestamp/原文件名.ext};保留原文件名
  55 + * false:{@code yyyyMMdd/原文件名_timestamp.ext};时间戳拼到文件名
  56 + */
  57 + static boolean PATH_TIMESTAMP_AS_DIRECTORY = true;
51 58
52 @Resource 59 @Resource
53 private FileConfigService fileConfigService; 60 private FileConfigService fileConfigService;
@@ -102,12 +109,22 @@ public class FileServiceImpl implements FileService { @@ -102,12 +109,22 @@ public class FileServiceImpl implements FileService {
102 } 109 }
103 String suffix = null; 110 String suffix = null;
104 if (PATH_SUFFIX_TIMESTAMP_ENABLE) { 111 if (PATH_SUFFIX_TIMESTAMP_ENABLE) {
  112 + // 5 位随机数,避免同一毫秒内的重复
105 suffix = String.valueOf(System.currentTimeMillis()) + RandomUtil.randomInt(10000, 100000); 113 suffix = String.valueOf(System.currentTimeMillis()) + RandomUtil.randomInt(10000, 100000);
106 } 114 }
107 115
108 // 2.1 先拼接 suffix 后缀 116 // 2.1 先拼接 suffix 后缀
109 if (StrUtil.isNotEmpty(suffix)) { 117 if (StrUtil.isNotEmpty(suffix)) {
110 - name = suffix + StrUtil.SLASH + name; 118 + if (PATH_TIMESTAMP_AS_DIRECTORY) {
  119 + name = suffix + StrUtil.SLASH + name;
  120 + } else {
  121 + String ext = FileUtil.extName(name);
  122 + if (StrUtil.isNotEmpty(ext)) {
  123 + name = FileUtil.mainName(name) + StrUtil.C_UNDERLINE + suffix + StrUtil.DOT + ext;
  124 + } else {
  125 + name = name + StrUtil.C_UNDERLINE + suffix;
  126 + }
  127 + }
111 } 128 }
112 // 2.2 再拼接 prefix 前缀 129 // 2.2 再拼接 prefix 前缀
113 if (StrUtil.isNotEmpty(prefix)) { 130 if (StrUtil.isNotEmpty(prefix)) {
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java
@@ -42,6 +42,7 @@ public class FileServiceImplTest extends BaseDbUnitTest { @@ -42,6 +42,7 @@ public class FileServiceImplTest extends BaseDbUnitTest {
42 public void setUp() { 42 public void setUp() {
43 FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; 43 FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true;
44 FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; 44 FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true;
  45 + FileServiceImpl.PATH_TIMESTAMP_AS_DIRECTORY = true;
45 } 46 }
46 47
47 @Test 48 @Test
@@ -291,6 +292,57 @@ public class FileServiceImplTest extends BaseDbUnitTest { @@ -291,6 +292,57 @@ public class FileServiceImplTest extends BaseDbUnitTest {
291 } 292 }
292 293
293 @Test 294 @Test
  295 + public void testGenerateUploadPath_TimestampAsName_AllEnabled() {
  296 + // 准备参数
  297 + String name = "test.jpg";
  298 + String directory = "avatar";
  299 + FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true;
  300 + FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true;
  301 + FileServiceImpl.PATH_TIMESTAMP_AS_DIRECTORY = false;
  302 +
  303 + // 调用
  304 + String path = fileService.generateUploadPath(name, directory);
  305 +
  306 + // 断言
  307 + // 格式为:avatar/yyyyMMdd/test_timestamp.jpg
  308 + assertTrue(path.matches(directory + "/\\d{8}/test_\\d+\\.jpg"));
  309 + }
  310 +
  311 + @Test
  312 + public void testGenerateUploadPath_TimestampAsName_PrefixDisabled() {
  313 + // 准备参数
  314 + String name = "test.jpg";
  315 + String directory = "avatar";
  316 + FileServiceImpl.PATH_PREFIX_DATE_ENABLE = false;
  317 + FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true;
  318 + FileServiceImpl.PATH_TIMESTAMP_AS_DIRECTORY = false;
  319 +
  320 + // 调用
  321 + String path = fileService.generateUploadPath(name, directory);
  322 +
  323 + // 断言
  324 + // 格式为:avatar/test_timestamp.jpg
  325 + assertTrue(path.matches(directory + "/test_\\d+\\.jpg"));
  326 + }
  327 +
  328 + @Test
  329 + public void testGenerateUploadPath_TimestampAsName_NoExtension() {
  330 + // 准备参数
  331 + String name = "test";
  332 + String directory = "avatar";
  333 + FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true;
  334 + FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true;
  335 + FileServiceImpl.PATH_TIMESTAMP_AS_DIRECTORY = false;
  336 +
  337 + // 调用
  338 + String path = fileService.generateUploadPath(name, directory);
  339 +
  340 + // 断言
  341 + // 格式为:avatar/yyyyMMdd/test_timestamp
  342 + assertTrue(path.matches(directory + "/\\d{8}/test_\\d+"));
  343 + }
  344 +
  345 + @Test
294 public void testGenerateUploadPath_DirectoryEmpty() { 346 public void testGenerateUploadPath_DirectoryEmpty() {
295 // 准备参数 347 // 准备参数
296 String name = "test.jpg"; 348 String name = "test.jpg";