diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java index 74a9361..6c042a0 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -53,6 +53,7 @@ public class S3FileClient extends AbstractFileClient { AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret())); URI endpoint = URI.create(buildEndpoint()); + URI presignerEndpoint = URI.create(buildPresignerEndpoint()); S3Configuration serviceConfiguration = S3Configuration.builder() // Path-style 访问 .pathStyleAccessEnabled(Boolean.TRUE.equals(config.getEnablePathStyleAccess())) .chunkedEncodingEnabled(false) // 禁用分块编码,参见 https://t.zsxq.com/kBy57 @@ -66,7 +67,7 @@ public class S3FileClient extends AbstractFileClient { presigner = S3Presigner.builder() .credentialsProvider(credentialsProvider) .region(region) - .endpointOverride(endpoint) + .endpointOverride(presignerEndpoint) .serviceConfiguration(serviceConfiguration) .build(); } @@ -162,6 +163,23 @@ public class S3FileClient extends AbstractFileClient { } /** + * presigner 节点地址 + * + * @return 节点地址 + */ + private String buildPresignerEndpoint() { + // 补全 domain + if (StrUtil.isEmpty(config.getDomain())) { + config.setDomain(buildDomain()); + } + + if (Boolean.TRUE.equals(config.getEnablePathStyleAccess())) { + return StrUtil.removeSuffix(config.getDomain(), StrUtil.format("/{}", config.getBucket())); + } + return StrUtil.replace(config.getDomain(), StrUtil.format("://{}.", config.getBucket()), "://"); + } + + /** * 解析 AWS 区域 * 优先级:配置的 region > 从 endpoint 解析的 region > 默认值 us-east-1 * diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java index 4e3bf80..1c0a3ab 100755 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.infra.service.file; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; @@ -93,7 +94,7 @@ public class FileConfigServiceImpl implements FileConfigService { fileConfigMapper.updateById(updateObj); // 清空缓存 - clearCache(config.getId(), null); + clearCache(config.getId(), config.getMaster()); } @Override @@ -132,7 +133,7 @@ public class FileConfigServiceImpl implements FileConfigService { fileConfigMapper.deleteById(id); // 清空缓存 - clearCache(id, null); + clearCache(id, config.getMaster()); } @Override @@ -149,7 +150,7 @@ public class FileConfigServiceImpl implements FileConfigService { fileConfigMapper.deleteByIds(ids); // 清空缓存 - ids.forEach(id -> clearCache(id, null)); + ids.forEach(id -> clearCache(id, false)); } /** @@ -191,7 +192,7 @@ public class FileConfigServiceImpl implements FileConfigService { validateFileConfigExists(id); // 上传文件 byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); - return getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg", "image/jpeg"); + return getFileClient(id).upload(content, "public" + StrUtil.SLASH + IdUtil.fastSimpleUUID() + ".jpg", "image/jpeg"); } @Override diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index 168db02..cfc85a7 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.infra.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.RandomUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.DigestUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -101,17 +102,12 @@ public class FileServiceImpl implements FileService { } String suffix = null; if (PATH_SUFFIX_TIMESTAMP_ENABLE) { - suffix = String.valueOf(System.currentTimeMillis()); + suffix = String.valueOf(System.currentTimeMillis()) + RandomUtil.randomInt(10000, 100000); } // 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; - } + name = suffix + StrUtil.SLASH + name; } // 2.2 再拼接 prefix 前缀 if (StrUtil.isNotEmpty(prefix)) { diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java index 9537ee0..4eb3b36 100644 --- a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java +++ b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java @@ -93,7 +93,7 @@ public class FileServiceImplTest extends BaseDbUnitTest { String url = randomString(); AtomicReference pathRef = new AtomicReference<>(); when(client.upload(same(content), argThat(path -> { - assertTrue(path.matches(directory + "/\\d{8}/" + name + "_\\d+.jpg")); + assertTrue(path.matches(directory + "/\\d{8}/\\d+/" + name + ".jpg")); pathRef.set(path); return true; }), eq(type))).thenReturn(url); @@ -125,7 +125,7 @@ public class FileServiceImplTest extends BaseDbUnitTest { String url = randomString(); AtomicReference pathRef = new AtomicReference<>(); when(client.upload(same(content), argThat(path -> { - assertTrue(path.matches("\\d{8}/6318848e882d8a7e7e82789d87608f684ee52d41966bfc8cad3ce15aad2b970e_\\d+\\.jpg")); + assertTrue(path.matches("\\d{8}/\\d+/6318848e882d8a7e7e82789d87608f684ee52d41966bfc8cad3ce15aad2b970e\\.jpg")); pathRef.set(path); return true; }), eq(type))).thenReturn(url); @@ -200,10 +200,10 @@ public class FileServiceImplTest extends BaseDbUnitTest { String path = fileService.generateUploadPath(name, directory); // 断言 - // 格式为:avatar/yyyyMMdd/test_timestamp.jpg + // 格式为:avatar/yyyyMMdd/timestamp/test.jpg assertTrue(path.startsWith(directory + "/")); // 包含日期格式:8 位数字,如 20240517 - assertTrue(path.matches(directory + "/\\d{8}/test_\\d+\\.jpg")); + assertTrue(path.matches(directory + "/\\d{8}/\\d+/test\\.jpg")); } @Test @@ -236,9 +236,9 @@ public class FileServiceImplTest extends BaseDbUnitTest { String path = fileService.generateUploadPath(name, directory); // 断言 - // 格式为:avatar/test_timestamp.jpg + // 格式为:avatar/timestamp/test.jpg assertTrue(path.startsWith(directory + "/")); - assertTrue(path.matches(directory + "/test_\\d+\\.jpg")); + assertTrue(path.matches(directory + "/\\d+/test\\.jpg")); } @Test @@ -269,9 +269,9 @@ public class FileServiceImplTest extends BaseDbUnitTest { String path = fileService.generateUploadPath(name, directory); // 断言 - // 格式为:avatar/yyyyMMdd/test_timestamp + // 格式为:avatar/yyyyMMdd/timestamp/test assertTrue(path.startsWith(directory + "/")); - assertTrue(path.matches(directory + "/\\d{8}/test_\\d+")); + assertTrue(path.matches(directory + "/\\d{8}/\\d+/test")); } @Test @@ -286,8 +286,8 @@ public class FileServiceImplTest extends BaseDbUnitTest { String path = fileService.generateUploadPath(name, directory); // 断言 - // 格式为:yyyyMMdd/test_timestamp.jpg - assertTrue(path.matches("\\d{8}/test_\\d+\\.jpg")); + // 格式为:yyyyMMdd/timestamp/test.jpg + assertTrue(path.matches("\\d{8}/\\d+/test\\.jpg")); } @Test @@ -302,8 +302,8 @@ public class FileServiceImplTest extends BaseDbUnitTest { String path = fileService.generateUploadPath(name, directory); // 断言 - // 格式为:yyyyMMdd/test_timestamp.jpg - assertTrue(path.matches("\\d{8}/test_\\d+\\.jpg")); + // 格式为:yyyyMMdd/timestamp/test.jpg + assertTrue(path.matches("\\d{8}/\\d+/test\\.jpg")); } }