From 2b6f4df3262ee53e7130adc2dbb8876112a1800c Mon Sep 17 00:00:00 2001 From: wuzongyong <13203449218@163.com> Date: Thu, 8 Jan 2026 09:16:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(file):=20=E4=B8=BAS3=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=B7=BB=E5=8A=A0=E9=A2=84=E7=AD=BE?= =?UTF-8?q?=E5=90=8DURL=E7=BC=93=E5=AD=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入RedisTemplate依赖用于缓存预签名URL - 添加Redis缓存配置,设置缓存前缀和50分钟过期时间 - 实现预签名URL的缓存读取和存储逻辑 - 添加延迟加载RedisTemplate的方法避免循环依赖 - 在文件删除时同步清除对应的缓存项 - 优化预签名URL生成流程,优先从缓存获取 --- .../file/core/client/s3/S3FileClient.java | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/zt-module-infra/zt-module-infra-server/src/main/java/com/zt/plat/module/infra/framework/file/core/client/s3/S3FileClient.java b/zt-module-infra/zt-module-infra-server/src/main/java/com/zt/plat/module/infra/framework/file/core/client/s3/S3FileClient.java index 7b716ba8..7e9fd653 100644 --- a/zt-module-infra/zt-module-infra-server/src/main/java/com/zt/plat/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/zt-module-infra/zt-module-infra-server/src/main/java/com/zt/plat/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -6,6 +6,7 @@ import cn.hutool.http.HttpUtil; import com.zt.plat.framework.common.util.spring.SpringUtils; import com.zt.plat.module.infra.framework.file.core.client.AbstractFileClient; import org.apache.commons.lang3.StringUtils; +import org.springframework.data.redis.core.RedisTemplate; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; @@ -22,6 +23,7 @@ import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignReques import java.net.URI; import java.time.Duration; +import java.util.concurrent.TimeUnit; /** * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 @@ -32,6 +34,15 @@ public class S3FileClient extends AbstractFileClient { private static final Duration DEFAULT_PRESIGNED_EXPIRATION = Duration.ofHours(24); private static final String PRESIGN_EXPIRE_SECONDS_PROPERTY = "zt.file.download-expire-seconds"; + /** + * Redis 缓存 key 前缀:文件预签名 URL + */ + private static final String CACHE_KEY_PREFIX = "file:presigned:url:"; + /** + * Redis 缓存时间:50 分钟 + */ + private static final long CACHE_EXPIRE_MINUTES = 50L; + /** * 生成临时下载地址(预签名下载 URL) * @param path 文件路径 @@ -45,6 +56,17 @@ public class S3FileClient extends AbstractFileClient { return StringUtils.EMPTY; } + // 1. 尝试从 Redis 缓存中获取 + String cacheKey = CACHE_KEY_PREFIX + path; + RedisTemplate redis = getRedisTemplate(); + if (redis != null) { + Object cachedUrl = redis.opsForValue().get(cacheKey); + if (cachedUrl instanceof String) { + return (String) cachedUrl; + } + } + + // 2. 缓存未命中,调用 S3 生成预签名 URL // 使用 S3 官方支持的 responseCacheControl 参数,强制浏览器和代理不缓存 GetObjectRequest.Builder getObjectRequestBuilder = GetObjectRequest.builder() .bucket(config.getBucket()) @@ -54,12 +76,37 @@ public class S3FileClient extends AbstractFileClient { .signatureDuration(realExpiration) .getObjectRequest(getObjectRequestBuilder.build()) .build(); - return presigner.presignGetObject(getObjectPresignRequest).url().toString(); + String presignedUrl = presigner.presignGetObject(getObjectPresignRequest).url().toString(); + + // 3. 将生成的 URL 存入 Redis 缓存 + if (redis != null && presignedUrl != null && !presignedUrl.isEmpty()) { + redis.opsForValue().set(cacheKey, presignedUrl, CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES); + } + + return presignedUrl; + } + + /** + * 获取 RedisTemplate 实例(延迟加载,避免初始化时循环依赖) + */ + @SuppressWarnings("unchecked") + private RedisTemplate getRedisTemplate() { + if (redisTemplate == null) { + try { + redisTemplate = SpringUtils.getBean("redisTemplate", RedisTemplate.class); + } catch (Exception e) { + // Redis 不可用时,不影响正常功能,只是不使用缓存 + return null; + } + } + return redisTemplate; } private S3Client client; private S3Presigner presigner; + private RedisTemplate redisTemplate; + public S3FileClient(Long id, S3FileClientConfig config) { super(id, config); } @@ -115,6 +162,13 @@ public class S3FileClient extends AbstractFileClient { .key(path) .build(); client.deleteObject(deleteRequest); + + // 删除文件后,清除对应的缓存 + String cacheKey = CACHE_KEY_PREFIX + path; + RedisTemplate redis = getRedisTemplate(); + if (redis != null) { + redis.delete(cacheKey); + } } @Override