fix(#758): guanyu (文件合入)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
# HealthLink-HIS 代码模块索引
|
# HealthLink-HIS 代码模块索引
|
||||||
|
|
||||||
> 供 LLM 快速定位代码。每个模块列出 Controller → Service → Mapper 关键文件。
|
> 供 LLM 快速定位代码。每个模块列出 Controller → Service → Mapper 关键文件。
|
||||||
|
> 最后更新: 2026-06-13 12:00 (298 个 Controller)
|
||||||
|
|
||||||
## 关键词 → 模块速查
|
## 关键词 → 模块速查
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package com.core.common.utils;
|
package com.core.common.utils;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.core.common.constant.CacheConstants;
|
import com.core.common.constant.CacheConstants;
|
||||||
import com.core.common.core.domain.entity.SysDictData;
|
import com.core.common.core.domain.entity.SysDictData;
|
||||||
import com.core.common.core.redis.RedisCache;
|
import com.core.common.core.redis.RedisCache;
|
||||||
import com.core.common.utils.spring.SpringUtils;
|
import com.core.common.utils.spring.SpringUtils;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ import java.util.List;
|
|||||||
* @author system
|
* @author system
|
||||||
*/
|
*/
|
||||||
public class DictUtils {
|
public class DictUtils {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(DictUtils.class);
|
||||||
/**
|
/**
|
||||||
* 分隔符
|
* 分隔符
|
||||||
*/
|
*/
|
||||||
@@ -39,24 +41,39 @@ public class DictUtils {
|
|||||||
* @return dictDatas 字典数据列表
|
* @return dictDatas 字典数据列表
|
||||||
*/
|
*/
|
||||||
public static List<SysDictData> getDictCache(String key) {
|
public static List<SysDictData> getDictCache(String key) {
|
||||||
Object cached = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
|
try {
|
||||||
if (StringUtils.isNull(cached)) {
|
Object cached = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
|
||||||
|
if (cached == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (cached instanceof JSONArray arrayCache) {
|
||||||
|
return arrayCache.toList(SysDictData.class);
|
||||||
|
}
|
||||||
|
if (cached instanceof List<?> list) {
|
||||||
|
// Redis缓存可能已反序列化为List,尝试逐个转换
|
||||||
|
java.util.ArrayList<SysDictData> result = new java.util.ArrayList<>(list.size());
|
||||||
|
for (Object item : list) {
|
||||||
|
if (item instanceof SysDictData dictData) {
|
||||||
|
result.add(dictData);
|
||||||
|
} else {
|
||||||
|
// 尝试通过JSON转换
|
||||||
|
String json = com.alibaba.fastjson2.JSON.toJSONString(item);
|
||||||
|
result.add(com.alibaba.fastjson2.JSON.parseObject(json, SysDictData.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
log.warn("字典缓存key={}的数据类型异常: {}, 清除缓存", key, cached.getClass().getName());
|
||||||
|
removeDictCache(key);
|
||||||
|
return null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("获取字典缓存异常key={}, 清除缓存: {}", key, e.getMessage());
|
||||||
|
try {
|
||||||
|
removeDictCache(key);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// 如果已经是目标类型,直接返回
|
|
||||||
if (cached instanceof List && ((List<?>) cached).stream().allMatch(e -> e instanceof SysDictData)) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<SysDictData> result = (List<SysDictData>) cached;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,14 +9,16 @@ import org.aspectj.lang.annotation.Around;
|
|||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Aspect
|
@Aspect
|
||||||
@Component
|
@Component
|
||||||
@@ -24,137 +26,154 @@ public class DictAspect {
|
|||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(DictAspect.class);
|
private static final Logger log = LoggerFactory.getLogger(DictAspect.class);
|
||||||
|
|
||||||
@Autowired
|
private final JdbcTemplate jdbcTemplate;
|
||||||
private JdbcTemplate jdbcTemplate; // 使用 JdbcTemplate 执行 SQL
|
|
||||||
|
public DictAspect(JdbcTemplate jdbcTemplate) {
|
||||||
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
@Around("@annotation(org.springframework.web.bind.annotation.GetMapping) || "
|
@Around("@annotation(org.springframework.web.bind.annotation.GetMapping) || "
|
||||||
+ "@annotation(org.springframework.web.bind.annotation.PostMapping)")
|
+ "@annotation(org.springframework.web.bind.annotation.PostMapping)")
|
||||||
public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {
|
public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
Object result = joinPoint.proceed(); // 执行原方法
|
Object result = joinPoint.proceed();
|
||||||
|
|
||||||
if (result instanceof R<?> response) {
|
try {
|
||||||
Object data = response.getData(); // 获取 R<?> 中的实际数据
|
if (result instanceof R<?> response) {
|
||||||
|
Object data = response.getData();
|
||||||
if (data instanceof Page) {
|
if (data instanceof Page<?> page) {
|
||||||
// 如果数据是 Page 类型,处理分页数据
|
List<?> records = page.getRecords();
|
||||||
Page<?> page = (Page<?>)data;
|
|
||||||
List<?> records = page.getRecords();
|
|
||||||
if (!records.isEmpty()) {
|
|
||||||
for (Object obj : records) {
|
for (Object obj : records) {
|
||||||
processDict(obj); // 处理每个 DTO 对象
|
processDict(obj, new HashSet<>());
|
||||||
}
|
}
|
||||||
}
|
} else if (data instanceof List<?> list) {
|
||||||
} else if (data instanceof List<?> list) {
|
|
||||||
if (!list.isEmpty()) {
|
|
||||||
for (Object obj : list) {
|
for (Object obj : list) {
|
||||||
processDict(obj); // 处理每个 DTO 对象
|
processDict(obj, new HashSet<>());
|
||||||
}
|
}
|
||||||
|
} else if (data != null) {
|
||||||
|
processDict(data, new HashSet<>());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// 如果数据是单个 DTO 对象,直接处理
|
|
||||||
processDict(data);
|
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("字典翻译处理异常,跳过字典处理", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void processDict(T dto) throws IllegalAccessException {
|
private void processDict(Object dto, Set<Integer> visited) {
|
||||||
if (dto == null) {
|
if (dto == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 检查对象是否是 DTO 类(即是否有 @Dict 注解的字段)
|
int identityHash = System.identityHashCode(dto);
|
||||||
boolean isDto = false;
|
if (!visited.add(identityHash)) {
|
||||||
for (Field field : dto.getClass().getDeclaredFields()) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?> clazz = dto.getClass();
|
||||||
|
if (clazz.isPrimitive() || clazz.getName().startsWith("java.lang.")
|
||||||
|
|| dto instanceof java.math.BigDecimal || dto instanceof java.util.Date
|
||||||
|
|| dto instanceof java.time.temporal.TemporalAccessor
|
||||||
|
|| dto instanceof byte[] || dto instanceof char[]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Field> allFields = collectFields(clazz);
|
||||||
|
boolean hasDict = false;
|
||||||
|
for (Field field : allFields) {
|
||||||
if (field.isAnnotationPresent(Dict.class)) {
|
if (field.isAnnotationPresent(Dict.class)) {
|
||||||
isDto = true;
|
hasDict = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 如果不是 DTO 类,直接返回
|
if (!hasDict) {
|
||||||
if (!isDto) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 获取 DTO 类的所有字段
|
|
||||||
for (Field field : dto.getClass().getDeclaredFields()) {
|
for (Field field : allFields) {
|
||||||
field.setAccessible(true); // 设置字段可访问
|
field.setAccessible(true);
|
||||||
Object fieldValue = field.get(dto); // 获取字段值
|
Object fieldValue;
|
||||||
|
try {
|
||||||
|
fieldValue = field.get(dto);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
log.debug("无法访问字段 {}.{}", clazz.getSimpleName(), field.getName());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (fieldValue == null) {
|
if (fieldValue == null) {
|
||||||
continue; // 如果字段值为空,跳过
|
continue;
|
||||||
}
|
}
|
||||||
// 如果字段是 List 类型,递归处理其中的每个元素
|
|
||||||
if (fieldValue instanceof List<?> list) {
|
if (fieldValue instanceof List<?> list) {
|
||||||
for (Object item : list) {
|
for (Object item : list) {
|
||||||
processDict(item); // 递归处理 List 中的每个元素
|
processDict(item, visited);
|
||||||
}
|
}
|
||||||
} else if (field.isAnnotationPresent(Dict.class)) {
|
} else if (field.isAnnotationPresent(Dict.class)) {
|
||||||
// 如果字段带有 @Dict 注解,处理字典值
|
|
||||||
Dict dictAnnotation = field.getAnnotation(Dict.class);
|
Dict dictAnnotation = field.getAnnotation(Dict.class);
|
||||||
String dictCode = dictAnnotation.dictCode();
|
String dictCode = dictAnnotation.dictCode();
|
||||||
String dictText = dictAnnotation.dictText();
|
String dictText = dictAnnotation.dictText();
|
||||||
String dictTable = dictAnnotation.dictTable();
|
String dictTable = dictAnnotation.dictTable();
|
||||||
String deleteFlag = dictAnnotation.deleteFlag();
|
String deleteFlag = dictAnnotation.deleteFlag();
|
||||||
|
|
||||||
// 检查 _dictText 字段是否已被手动填充(如控制器方法中预先查询设置)
|
|
||||||
// 如果已非空则跳过 SQL 查询,避免覆盖有效值
|
|
||||||
String textFieldName = field.getName() + "_dictText";
|
String textFieldName = field.getName() + "_dictText";
|
||||||
try {
|
try {
|
||||||
Field existingTextField = dto.getClass().getDeclaredField(textFieldName);
|
Field existingTextField = clazz.getDeclaredField(textFieldName);
|
||||||
existingTextField.setAccessible(true);
|
existingTextField.setAccessible(true);
|
||||||
Object existingValue = existingTextField.get(dto);
|
Object existingValue = existingTextField.get(dto);
|
||||||
if (existingValue != null && !existingValue.toString().isEmpty()) {
|
if (existingValue != null && !existingValue.toString().isEmpty()) {
|
||||||
continue; // _dictText 已有值,跳过
|
continue;
|
||||||
}
|
}
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
// _dictText 字段不存在,继续正常流程
|
// _dictText field not present, proceed normally
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询字典值
|
try {
|
||||||
String dictLabel = queryDictLabel(dictTable, dictCode, dictText, deleteFlag, fieldValue.toString());
|
String dictLabel = queryDictLabel(dictTable, dictCode, dictText, deleteFlag, fieldValue.toString());
|
||||||
if (dictLabel != null && !dictLabel.isEmpty()) {
|
if (dictLabel != null && !dictLabel.isEmpty()) {
|
||||||
// 动态生成 _dictText 字段名
|
try {
|
||||||
try {
|
Field textField = clazz.getDeclaredField(textFieldName);
|
||||||
Field textField = dto.getClass().getDeclaredField(textFieldName);
|
textField.setAccessible(true);
|
||||||
textField.setAccessible(true);
|
textField.set(dto, dictLabel);
|
||||||
textField.set(dto, dictLabel); // 设置 _dictText 字段的值
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
} catch (NoSuchFieldException e) {
|
log.debug("字段 {} 不存在或无法访问,跳过字典翻译", textFieldName);
|
||||||
// 如果 _dictText 字段不存在,忽略错误
|
}
|
||||||
log.debug("字段 {} 不存在,跳过字典翻译", textFieldName);
|
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("字典翻译异常, 字段={}, dictCode={}, 跳过: {}", field.getName(), dictCode, e.getMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
processDict(fieldValue); // 递归处理 Dto 中的每个元素
|
processDict(fieldValue, visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Field> collectFields(Class<?> clazz) {
|
||||||
|
List<Field> fields = new ArrayList<>();
|
||||||
|
Class<?> current = clazz;
|
||||||
|
while (current != null && current != Object.class) {
|
||||||
|
for (Field field : current.getDeclaredFields()) {
|
||||||
|
fields.add(field);
|
||||||
|
}
|
||||||
|
current = current.getSuperclass();
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
private String queryDictLabel(String dictTable, String dictCode, String dictText, String deleteFlag, String dictValue) {
|
private String queryDictLabel(String dictTable, String dictCode, String dictText, String deleteFlag, String dictValue) {
|
||||||
if (!StringUtils.hasText(dictTable)) {
|
if (!StringUtils.hasText(dictTable)) {
|
||||||
// 场景 1:默认字典走DictUtils缓存(dictTable 为空时)
|
|
||||||
return DictUtils.getDictLabel(dictCode, dictValue);
|
return DictUtils.getDictLabel(dictCode, dictValue);
|
||||||
} else {
|
}
|
||||||
// 场景 2:查询指定表(dictTable 有值时)
|
if (!StringUtils.hasText(dictText)) {
|
||||||
// 必须同时有 dictTable 和 dictText 才能执行 SQL 查询
|
return DictUtils.getDictLabel(dictCode, dictValue);
|
||||||
if (!StringUtils.hasText(dictText)) {
|
}
|
||||||
// 如果 dictText 为空,回退到字典缓存查询
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
return DictUtils.getDictLabel(dictCode, dictValue);
|
sqlBuilder.append(String.format("SELECT %s FROM %s WHERE %s::varchar = ?", dictText, dictTable, dictCode));
|
||||||
}
|
if (StringUtils.hasText(deleteFlag)) {
|
||||||
// 构建SQL,支持 delete_flag 过滤
|
sqlBuilder.append(String.format(" AND %s = '0'", deleteFlag));
|
||||||
StringBuilder sqlBuilder = new StringBuilder();
|
}
|
||||||
sqlBuilder.append(String.format("SELECT %s FROM %s WHERE %s::varchar = ?", dictText, dictTable, dictCode));
|
sqlBuilder.append(" LIMIT 1");
|
||||||
// 如果指定了 deleteFlag 字段名,添加过滤条件
|
try {
|
||||||
if (StringUtils.hasText(deleteFlag)) {
|
return jdbcTemplate.queryForObject(sqlBuilder.toString(), String.class, dictValue);
|
||||||
sqlBuilder.append(String.format(" AND %s = '0'", deleteFlag));
|
} catch (DataAccessException e) {
|
||||||
}
|
return "";
|
||||||
sqlBuilder.append(" LIMIT 1");
|
|
||||||
String sql = sqlBuilder.toString();
|
|
||||||
try {
|
|
||||||
return jdbcTemplate.queryForObject(sql, String.class, dictValue);
|
|
||||||
} catch (DataAccessException e) {
|
|
||||||
// 如果查询结果为空,返回 空字符串
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user