From e11d3e1b6ebf7c0c1696cb152b190c8e21967f09 Mon Sep 17 00:00:00 2001 From: lzh Date: Sun, 22 Mar 2026 14:59:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(framework):=20OssPresignResponseBodyAdvice?= =?UTF-8?q?=20=E6=94=AF=E6=8C=81=20List=20=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E9=A2=84=E7=AD=BE=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - @OssPresignUrl 注解现在同时适用于 String 和 List 字段 - 回填时防御不可变 List,自动降级为 ArrayList - FileServiceImpl 预签名访问 URL 去除查询参数,保持持久化路径干净 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../core/OssPresignResponseBodyAdvice.java | 41 +++++++++++++++++-- .../infra/service/file/FileServiceImpl.java | 2 +- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/viewsh-framework/viewsh-spring-boot-starter-web/src/main/java/com/viewsh/framework/web/core/presign/core/OssPresignResponseBodyAdvice.java b/viewsh-framework/viewsh-spring-boot-starter-web/src/main/java/com/viewsh/framework/web/core/presign/core/OssPresignResponseBodyAdvice.java index 4d94d95..02063d8 100644 --- a/viewsh-framework/viewsh-spring-boot-starter-web/src/main/java/com/viewsh/framework/web/core/presign/core/OssPresignResponseBodyAdvice.java +++ b/viewsh-framework/viewsh-spring-boot-starter-web/src/main/java/com/viewsh/framework/web/core/presign/core/OssPresignResponseBodyAdvice.java @@ -130,8 +130,21 @@ public class OssPresignResponseBodyAdvice implements ResponseBodyAdvice String signed = signedMap.get(entry.url); if (signed != null) { try { - entry.field.set(entry.target, signed); - } catch (IllegalAccessException e) { + if (entry.isList()) { + @SuppressWarnings("unchecked") + List list = (List) entry.field.get(entry.target); + try { + list.set(entry.index(), signed); + } catch (UnsupportedOperationException ex) { + // 不可变 List(如 List.of()),替换为可变 ArrayList 后重试 + List mutable = new ArrayList<>(list); + mutable.set(entry.index(), signed); + entry.field.set(entry.target, mutable); + } + } else { + entry.field.set(entry.target, signed); + } + } catch (Exception e) { log.warn("[OssPresignResponseBodyAdvice] 回填签名 URL 失败: field={}", entry.field.getName(), e); } } @@ -195,6 +208,15 @@ public class OssPresignResponseBodyAdvice implements ResponseBodyAdvice if (value instanceof String url && StrUtil.isNotEmpty(url)) { entries.add(new FieldEntry(obj, field, url)); } + // 带注解的 List 字段:逐个收集 URL + if (value instanceof List list) { + for (int i = 0; i < list.size(); i++) { + Object item = list.get(i); + if (item instanceof String url && StrUtil.isNotEmpty(url)) { + entries.add(new FieldEntry(obj, field, i, url)); + } + } + } } else { // 非简单类型字段:递归(递归入口会再次判断 isProjectClass) collectUrls(value, entries, visited, depth + 1); @@ -221,7 +243,8 @@ public class OssPresignResponseBodyAdvice implements ResponseBodyAdvice return FIELD_CACHE.computeIfAbsent(clazz, c -> { Set result = new HashSet<>(); for (Field field : getAllFields(c)) { - if (field.isAnnotationPresent(OssPresignUrl.class) && field.getType() == String.class) { + if (field.isAnnotationPresent(OssPresignUrl.class) + && (field.getType() == String.class || List.class.isAssignableFrom(field.getType()))) { result.add(field); } } @@ -340,6 +363,16 @@ public class OssPresignResponseBodyAdvice implements ResponseBodyAdvice } } - private record FieldEntry(Object target, Field field, String url) {} + private record FieldEntry(Object target, Field field, int index, String url) { + + /** String 字段构造 */ + FieldEntry(Object target, Field field, String url) { + this(target, field, -1, url); + } + + boolean isList() { + return index >= 0; + } + } } diff --git a/viewsh-module-infra/viewsh-module-infra-server/src/main/java/com/viewsh/module/infra/service/file/FileServiceImpl.java b/viewsh-module-infra/viewsh-module-infra-server/src/main/java/com/viewsh/module/infra/service/file/FileServiceImpl.java index c3ee76e..a2bba8d 100644 --- a/viewsh-module-infra/viewsh-module-infra-server/src/main/java/com/viewsh/module/infra/service/file/FileServiceImpl.java +++ b/viewsh-module-infra/viewsh-module-infra-server/src/main/java/com/viewsh/module/infra/service/file/FileServiceImpl.java @@ -134,7 +134,7 @@ public class FileServiceImpl implements FileService { // 2. 获取文件预签名地址 FileClient fileClient = fileConfigService.getMasterFileClient(); String uploadUrl = fileClient.presignPutUrl(path); - String visitUrl = fileClient.presignGetUrl(path, null); + String visitUrl = HttpUtils.removeUrlQuery(fileClient.presignGetUrl(path, null)); return new FilePresignedUrlRespVO().setConfigId(fileClient.getId()) .setPath(path).setUploadUrl(uploadUrl).setUrl(visitUrl); }