Files
his/MD/bugs/BUG_758_ANALYSIS.md

123 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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<List<DiagnosisQueryDto>>
→ DictAspect 拦截 @GetMapping 响应
→ processDict() 发现 DiagnosisQueryDto.medTypeCode 有 @Dict(dictCode = "med_type")
→ DictUtils.getDictLabel("med_type", value)
→ DictUtils.getDictCache("med_type")
→ mapper.convertValue(cached, TypeReference<List<SysDictData>>) ← 💥 这里抛异常
→ DictAspect 无 try-catch异常直接传播到前端
```
**根因:`DictUtils.getDictCache()` 缺少异常处理**
- 文件:`core-common/src/main/java/com/core/common/utils/DictUtils.java:38-62`
- Redis 中的字典缓存数据结构异常(可能是旧 Fastjson 序列化格式遗留、嵌套数组等)
- Jackson `ObjectMapper.convertValue()` 无法将异常结构转为 `List<SysDictData>`,抛出 `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<SysDictData> 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<SysDictData> result = (List<SysDictData>) cached;
return result;
}
try {
com.fasterxml.jackson.core.type.TypeReference<List<SysDictData>> typeRef =
new com.fasterxml.jackson.core.type.TypeReference<List<SysDictData>>() {};
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 文件的异常处理逻辑,纯后端修复,无需前端改动。