From 93447b0e468b6e6beb3742ea868841999a6fdbd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=8E=E4=BD=97?= Date: Fri, 12 Jun 2026 15:34:50 +0800 Subject: [PATCH] =?UTF-8?q?docs(bug):=20=E8=AF=B8=E8=91=9B=E4=BA=AE?= =?UTF-8?q?=E5=88=86=E6=9E=90=E6=8A=A5=E5=91=8A=20Bug=20#758?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MD/bugs/BUG_758_ANALYSIS.md | 122 ++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 MD/bugs/BUG_758_ANALYSIS.md diff --git a/MD/bugs/BUG_758_ANALYSIS.md b/MD/bugs/BUG_758_ANALYSIS.md new file mode 100644 index 000000000..dff43371d --- /dev/null +++ b/MD/bugs/BUG_758_ANALYSIS.md @@ -0,0 +1,122 @@ +# Bug #758 诸葛亮分析报告 + +> **文档类型**: Bug分析 +> **分析时间**: 2026-06-12 15:34:50 +> **分析模型**: mimo-v2.5 (LLM深度分析) + +--- + +## 基本信息 +- **Bug #**: 758 +- **标题**: 【门诊医生工作站-检验】检验信息下的新增的字段按钮点击会出现报错Cannot deserialize value of type `com.core.common.core.domain.entity.SysDictData` from Array value +- **模块**: 门诊医生工作站 +- **提出人**: 王栩坤 + +--- + +I now have a complete understanding of the root cause. Let me provide the analysis. + +--- + +### 一、Bug 理解 + +用户在门诊医生工作站的"检验信息"区域点击"新增"按钮时,页面弹出 Jackson 反序列化错误 `Cannot deserialize value of type SysDictData from Array value`,无法正常新增检验信息。期望点击新增后能正常清空表单、准备录入新检验申请单。 + +### 二、根因分析 + +**错误触发链路:** + +``` +用户点击"新增" +→ handleNewApplication() +→ resetForm() +→ getEncounterDiagnosis(encounterId) [API 调用] +→ 后端返回 R> +→ DictAspect 拦截 @GetMapping 响应 +→ processDict() 发现 DiagnosisQueryDto.medTypeCode 有 @Dict(dictCode = "med_type") +→ DictUtils.getDictLabel("med_type", value) +→ DictUtils.getDictCache("med_type") +→ mapper.convertValue(cached, TypeReference>) ← 💥 这里抛异常 +→ DictAspect 无 try-catch,异常直接传播到前端 +``` + +**根因:`DictUtils.getDictCache()` 缺少异常处理** + +- 文件:`core-common/src/main/java/com/core/common/utils/DictUtils.java:38-62` +- Redis 中的字典缓存数据结构异常(可能是旧 Fastjson 序列化格式遗留、嵌套数组等) +- Jackson `ObjectMapper.convertValue()` 无法将异常结构转为 `List`,抛出 `JsonMappingException` +- 该异常未被 `DictUtils` 或 `DictAspect` 捕获,直接传播为 HTTP 500 错误 + +**涉及的关键文件:** +1. `core-common/src/main/java/com/core/common/utils/DictUtils.java` — `getDictCache()` 方法(核心问题) +2. `healthlink-his-common/src/main/java/com/healthlink/his/common/aspectj/DictAspect.java` — `processDict()` 方法(缺少异常保护) +3. `healthlink-his-application/src/main/java/com/healthlink/his/web/doctorstation/controller/DoctorStationDiagnosisController.java` — 被 DictAspect 拦截的控制器 +4. `healthlink-his-application/src/main/java/com/healthlink/his/web/doctorstation/dto/DiagnosisQueryDto.java` — 含 `@Dict` 注解的 DTO + +**与历史 Bug 的关联:** 此前 commit `babd8d0c0` 修复了类似问题(Jackson 配置从 ObjectMapper bean 改回 Jackson2ObjectMapperBuilderCustomizer),但 `DictUtils.getDictCache()` 的 `convertValue` 仍缺少防御性异常处理。 + +### 三、修复方案 + +**修改 1:`DictUtils.getDictCache()` 添加 try-catch 防御**(核心修复) + +文件:`core-common/src/main/java/com/core/common/utils/DictUtils.java` + +在 `getDictCache()` 方法中,为 `mapper.convertValue()` 添加 try-catch,失败时清理损坏缓存并返回 null: + +```java +public static List getDictCache(String key) { + Object cached = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); + if (StringUtils.isNull(cached)) { + return null; + } + if (cached instanceof List && ((List) cached).stream().allMatch(e -> e instanceof SysDictData)) { + @SuppressWarnings("unchecked") + List result = (List) cached; + return result; + } + try { + com.fasterxml.jackson.core.type.TypeReference> typeRef = + new com.fasterxml.jackson.core.type.TypeReference>() {}; + ObjectMapper mapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + if (cached instanceof JsonNode jsonNode) { + return mapper.convertValue(jsonNode, typeRef); + } + return mapper.convertValue(cached, typeRef); + } catch (Exception e) { + // 缓存数据格式异常,清理损坏缓存,下次重新加载 + org.slf4j.LoggerFactory.getLogger(DictUtils.class) + .warn("字典缓存转换失败(key={}),已清理: {}", key, e.getMessage()); + removeDictCache(key); + return null; + } +} +``` + +**修改 2:`DictAspect.processDict()` 添加 try-catch 防御**(防止字典翻译失败影响 API 响应) + +文件:`healthlink-his-common/src/main/java/com/healthlink/his/common/aspectj/DictAspect.java` + +在 `processDict()` 方法中,对字典查询部分包裹 try-catch: + +```java +} else if (field.isAnnotationPresent(Dict.class)) { + try { + // ... 原有字典翻译逻辑 ... + } catch (Exception e) { + log.debug("字段 {} 字典翻译失败,跳过: {}", field.getName(), e.getMessage()); + } +} +``` + +### 四、路由决策 + +**FIXER: guanyu(后端开发)** + +**REASON:** 修复涉及 `DictUtils`(core-common 模块)和 `DictAspect`(healthlink-his-common 模块)两个后端 Java 文件的异常处理逻辑,纯后端修复,无需前端改动。 + +--- + +## 路由决策 +- **修复 Agent**: guanyu +- **原因**: ** 修复涉及 `DictUtils`(core-common 模块)和 `DictAspect`(healthlink-his-common 模块)两个后端 Java 文件的异常处理逻辑,纯后端修复,无需前端改动。