@liruiyi962464
2025-07-25T08:13:06.000000Z
字数 42113
阅读 136
代码一.找到字典切面类(DictAspect)
二.改造方法(parseDictText)
三.修改后的parseDictText方法,支持IPage、List、Object,parseDictText 注释此方法,完后拷贝下方代码
private void parseDictText(Object result) {if (result instanceof Result) {List<Object> list = new LinkedList<>();if (((Result) result).getResult() instanceof IPage) {//分页list = ((IPage) ((Result) result).getResult()).getRecords();} else if (((Result) result).getResult() instanceof List) {//List集合list = (List<Object>) ((Result) result).getResult();}else{//单对象Object record = ((Result) result).getResult();//判断能否转换成JSON,因为有些结果集返回的是String类型,导致翻译异常,因此判断是否可以转换jsonif(checkIsJsonStr(record)){//字典翻译record = this.dictEscape(record);}((Result) result).setResult(record);}if(list != null && list.size() > 0){List<Object> items = new ArrayList<>();for(Object record : list){if(checkIsJsonStr(record)){//字典翻译record = this.dictEscape(record);}items.add(record);}if (((Result) result).getResult() instanceof IPage) {((IPage) ((Result) result).getResult()).setRecords(items);} else if (((Result) result).getResult() instanceof List) {((Result) result).setResult(items);}}}}
/*** 字典翻译* @param record* @return*/private JSONObject dictEscape(Object record){ObjectMapper mapper = new ObjectMapper();String json = "{}";JSONObject item = null;try {//解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormatjson = mapper.writeValueAsString(record);//对象序列化为JSON字符串} catch (JsonProcessingException e) {log.error("json解析失败" + e.getMessage(), e);}try {item = JSONObject.parseObject(json);//update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------for (Field field : oConvertUtils.getAllFields(record)) {//update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------if (field.getAnnotation(Dict.class) != null) {String code = field.getAnnotation(Dict.class).dicCode();String text = field.getAnnotation(Dict.class).dicText();String table = field.getAnnotation(Dict.class).dictTable();String key = String.valueOf(item.get(field.getName()));//翻译字典值对应的txtString textValue = key;//非中文时翻译if(!checkCountName(key)){textValue = translateDictValue(code, text, table, key);}log.debug(" 字典Val : " + textValue);log.debug(" __翻译字典字段__ " + field.getName() + CommonConstant.DICT_TEXT_SUFFIX + ": " + textValue);item.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);}//date类型默认转换string格式化日期if (field.getType().getName().equals("java.util.Date") && field.getAnnotation(JsonFormat.class) == null && item.get(field.getName()) != null) {SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));}}}catch (Exception e){log.info("字典翻译异常:"+e.getMessage(),e);}return item;}
/*** 检测是否是中文* @param countName* @return*/public static boolean checkCountName(String countName){Pattern p = Pattern.compile("[\u4e00-\u9fa5]");Matcher m = p.matcher(countName);if (m.find()) {return true;}return false;}
/*** 检测是否可转换为JSON字符串* @param record* @return*/public static boolean checkIsJsonStr(Object record){boolean jsonFlag = false;try {String json = new ObjectMapper().writeValueAsString(record);if(json.startsWith("{")) {jsonFlag = true;}} catch (JsonProcessingException e) {e.printStackTrace();}return jsonFlag;}
package org.jeecg.common.aspect;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.parser.Feature;import com.baomidou.mybatisplus.core.metadata.IPage;import com.fasterxml.jackson.annotation.JsonFormat;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.jeecg.common.api.CommonAPI;import org.jeecg.common.api.vo.Result;import org.jeecg.common.aspect.annotation.Dict;import org.jeecg.common.constant.CommonConstant;import org.jeecg.common.system.vo.DictModel;import org.jeecg.common.util.oConvertUtils;import org.jetbrains.annotations.NotNull;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Lazy;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import java.lang.reflect.Field;import java.text.SimpleDateFormat;import java.util.*;import java.util.concurrent.TimeUnit;import java.util.regex.Matcher;import java.util.regex.Pattern;import java.util.stream.Collectors;/*** @Description: 字典aop类* @Author: dangzhenghui* @Date: 2019-3-17 21:50* @Version: 1.0*/@Aspect@Component@Slf4jpublic class DictAspect {@Lazy@Autowiredprivate CommonAPI commonApi;@Autowiredpublic RedisTemplate redisTemplate;@Autowiredprivate ObjectMapper objectMapper;private static final String JAVA_UTIL_DATE = "java.util.Date";/*** 定义切点Pointcut*/@Pointcut("(@within(org.springframework.web.bind.annotation.RestController) || " +"@within(org.springframework.stereotype.Controller) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)) " +"&& execution(public org.jeecg.common.api.vo.Result org.jeecg..*.*(..))")public void excudeService() {}@Around("excudeService()")public Object doAround(@NotNull ProceedingJoinPoint pjp) throws Throwable {long time1=System.currentTimeMillis();Object result = pjp.proceed();long time2=System.currentTimeMillis();log.debug("获取JSON数据 耗时:"+(time2-time1)+"ms");long start=System.currentTimeMillis();// result=this.parseDictText(result);this.parseDictText(result);long end=System.currentTimeMillis();log.debug("注入字典到JSON数据 耗时"+(end-start)+"ms");return result;}/*** 本方法针对返回对象为Result 的IPage的分页列表数据进行动态字典注入* 字典注入实现 通过对实体类添加注解@dict 来标识需要的字典内容,字典分为单字典code即可 ,table字典 code table text配合使用与原来jeecg的用法相同* 示例为SysUser 字段为sex 添加了注解@Dict(dicCode = "sex") 会在字典服务立马查出来对应的text 然后在请求list的时候将这个字典text,已字段名称加_dictText形式返回到前端* 例输入当前返回值的就会多出一个sex_dictText字段* {* sex:1,* sex_dictText:"男"* }* 前端直接取值sext_dictText在table里面无需再进行前端的字典转换了* customRender:function (text) {* if(text==1){* return "男";* }else if(text==2){* return "女";* }else{* return text;* }* }* 目前vue是这么进行字典渲染到table上的多了就很麻烦了 这个直接在服务端渲染完成前端可以直接用* @param result*/// private Object parseDictText(Object result) {// //if (result instanceof Result) {// if (true) {// if (((Result) result).getResult() instanceof IPage) {// List<JSONObject> items = new ArrayList<>();//// //step.1 筛选出加了 Dict 注解的字段列表// List<Field> dictFieldList = new ArrayList<>();// // 字典数据列表, key = 字典code,value=数据列表// Map<String, List<String>> dataListMap = new HashMap<>(5);// //取出结果集// List<Object> records=((IPage) ((Result) result).getResult()).getRecords();// //update-begin--Author:zyf -- Date:20220606 ----for:【VUEN-1230】 判断是否含有字典注解,没有注解返回-----// Boolean hasDict= checkHasDict(records);// if(!hasDict){// return result;// }//// log.debug(" __ 进入字典翻译切面 DictAspect —— " );// //update-end--Author:zyf -- Date:20220606 ----for:【VUEN-1230】 判断是否含有字典注解,没有注解返回-----// for (Object record : records) {// String json="{}";// try {// //update-begin--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----// //解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat// json = objectMapper.writeValueAsString(record);// //update-end--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----// } catch (JsonProcessingException e) {// log.error("json解析失败"+e.getMessage(),e);// }// //update-begin--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----// JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);// //update-end--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----//// //update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------// //for (Field field : record.getClass().getDeclaredFields()) {// // 遍历所有字段,把字典Code取出来,放到 map 里// for (Field field : oConvertUtils.getAllFields(record)) {// String value = item.getString(field.getName());// if (oConvertUtils.isEmpty(value)) {// continue;// }// //update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------// if (field.getAnnotation(Dict.class) != null) {// if (!dictFieldList.contains(field)) {// dictFieldList.add(field);// }// String code = field.getAnnotation(Dict.class).dicCode();// String text = field.getAnnotation(Dict.class).dicText();// String table = field.getAnnotation(Dict.class).dictTable();// //update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// String dataSource = field.getAnnotation(Dict.class).ds();// //update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// List<String> dataList;// String dictCode = code;// if (!StringUtils.isEmpty(table)) {// //update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// dictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);// //update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// }// dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());// this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(",")));// }// //date类型默认转换string格式化日期// //update-begin--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----// //if (JAVA_UTIL_DATE.equals(field.getType().getName())&&field.getAnnotation(JsonFormat.class)==null&&item.get(field.getName())!=null){// //SimpleDateFormat aDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// // item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));// //}// //update-end--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----// }// items.add(item);// }//// //step.2 调用翻译方法,一次性翻译// Map<String, List<DictModel>> translText = this.translateAllDict(dataListMap);//// //step.3 将翻译结果填充到返回结果里// for (JSONObject record : items) {// for (Field field : dictFieldList) {// String code = field.getAnnotation(Dict.class).dicCode();// String text = field.getAnnotation(Dict.class).dicText();// String table = field.getAnnotation(Dict.class).dictTable();// //update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// // 自定义的字典表数据源// String dataSource = field.getAnnotation(Dict.class).ds();// //update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// String fieldDictCode = code;// if (!StringUtils.isEmpty(table)) {// //update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// fieldDictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);// //update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// }//// String value = record.getString(field.getName());// if (oConvertUtils.isNotEmpty(value)) {// List<DictModel> dictModels = translText.get(fieldDictCode);// if(dictModels==null || dictModels.size()==0){// continue;// }//// String textValue = this.translDictText(dictModels, value);// log.debug(" 字典Val : " + textValue);// log.debug(" __翻译字典字段__ " + field.getName() + CommonConstant.DICT_TEXT_SUFFIX + ": " + textValue);//// // TODO-sun 测试输出,待删// log.debug(" ---- dictCode: " + fieldDictCode);// log.debug(" ---- value: " + value);// log.debug(" ----- text: " + textValue);// log.debug(" ---- dictModels: " + JSON.toJSONString(dictModels));//// record.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);// }// }// }//// ((IPage) ((Result) result).getResult()).setRecords(items);// }//// }// return result;// }private void parseDictText(Object result) {if (result instanceof Result) {List<Object> list = new LinkedList<>();if (((Result) result).getResult() instanceof IPage) {//分页list = ((IPage) ((Result) result).getResult()).getRecords();} else if (((Result) result).getResult() instanceof List) {//List集合list = (List<Object>) ((Result) result).getResult();}else{//单对象Object record = ((Result) result).getResult();//判断能否转换成JSON,因为有些结果集返回的是String类型,导致翻译异常,因此判断是否可以转换jsonif(checkIsJsonStr(record)){//字典翻译record = this.dictEscape(record);}((Result) result).setResult(record);}if(list != null && list.size() > 0){List<Object> items = new ArrayList<>();for(Object record : list){if(checkIsJsonStr(record)){//字典翻译record = this.dictEscape(record);}items.add(record);}if (((Result) result).getResult() instanceof IPage) {((IPage) ((Result) result).getResult()).setRecords(items);} else if (((Result) result).getResult() instanceof List) {((Result) result).setResult(items);}}}}/*** 字典翻译* @param record* @return*/private JSONObject dictEscape(Object record){ObjectMapper mapper = new ObjectMapper();String json = "{}";JSONObject item = null;try {//解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormatjson = mapper.writeValueAsString(record);//对象序列化为JSON字符串} catch (JsonProcessingException e) {log.error("json解析失败" + e.getMessage(), e);}try {item = JSONObject.parseObject(json);//update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------for (Field field : oConvertUtils.getAllFields(record)) {//update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------if (field.getAnnotation(Dict.class) != null) {String code = field.getAnnotation(Dict.class).dicCode();String text = field.getAnnotation(Dict.class).dicText();String table = field.getAnnotation(Dict.class).dictTable();String key = String.valueOf(item.get(field.getName()));//翻译字典值对应的txtString textValue = key;//非中文时翻译if(!checkCountName(key)){textValue = translateDictValue(code, text, table, key);}log.debug(" 字典Val : " + textValue);log.debug(" __翻译字典字段__ " + field.getName() + CommonConstant.DICT_TEXT_SUFFIX + ": " + textValue);item.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);}//date类型默认转换string格式化日期if (field.getType().getName().equals("java.util.Date") && field.getAnnotation(JsonFormat.class) == null && item.get(field.getName()) != null) {SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));}}}catch (Exception e){log.info("字典翻译异常:"+e.getMessage(),e);}return item;}/*** 检测是否是中文* @param countName* @return*/public static boolean checkCountName(String countName){Pattern p = Pattern.compile("[\u4e00-\u9fa5]");Matcher m = p.matcher(countName);if (m.find()) {return true;}return false;}/*** 检测是否可转换为JSON字符串* @param record* @return*/public static boolean checkIsJsonStr(Object record){boolean jsonFlag = false;try {String json = new ObjectMapper().writeValueAsString(record);if(json.startsWith("{")) {jsonFlag = true;}} catch (JsonProcessingException e) {e.printStackTrace();}return jsonFlag;}/*** list 去重添加*/private void listAddAllDeduplicate(List<String> dataList, List<String> addList) {// 筛选出dataList中没有的数据List<String> filterList = addList.stream().filter(i -> !dataList.contains(i)).collect(Collectors.toList());dataList.addAll(filterList);}/*** 一次性把所有的字典都翻译了* 1. 所有的普通数据字典的所有数据只执行一次SQL* 2. 表字典相同的所有数据只执行一次SQL* @param dataListMap* @return*/private Map<String, List<DictModel>> translateAllDict(Map<String, List<String>> dataListMap) {// 翻译后的字典文本,key=dictCodeMap<String, List<DictModel>> translText = new HashMap<>(5);// 需要翻译的数据(有些可以从redis缓存中获取,就不走数据库查询)List<String> needTranslData = new ArrayList<>();//step.1 先通过redis中获取缓存字典数据for (String dictCode : dataListMap.keySet()) {List<String> dataList = dataListMap.get(dictCode);if (dataList.size() == 0) {continue;}// 表字典需要翻译的数据List<String> needTranslDataTable = new ArrayList<>();for (String s : dataList) {String data = s.trim();if (data.length() == 0) {continue; //跳过循环}if (dictCode.contains(",")) {String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, data);if (redisTemplate.hasKey(keyString)) {try {String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());list.add(new DictModel(data, text));} catch (Exception e) {log.warn(e.getMessage());}} else if (!needTranslDataTable.contains(data)) {// 去重添加needTranslDataTable.add(data);}} else {String keyString = String.format("sys:cache:dict::%s:%s", dictCode, data);if (redisTemplate.hasKey(keyString)) {try {String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());list.add(new DictModel(data, text));} catch (Exception e) {log.warn(e.getMessage());}} else if (!needTranslData.contains(data)) {// 去重添加needTranslData.add(data);}}}//step.2 调用数据库翻译表字典if (needTranslDataTable.size() > 0) {String[] arr = dictCode.split(",");String table = arr[0], text = arr[1], code = arr[2];String values = String.join(",", needTranslDataTable);//update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// 自定义的数据源String dataSource = null;if (arr.length > 3) {dataSource = arr[3];}//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------log.debug("translateDictFromTableByKeys.dictCode:" + dictCode);log.debug("translateDictFromTableByKeys.values:" + values);//update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------//update-begin---author:wangshuai---date:2024-01-09---for:微服务下为空报错没有参数需要传递空字符串---if(null == dataSource){dataSource = "";}//update-end---author:wangshuai---date:2024-01-09---for:微服务下为空报错没有参数需要传递空字符串---List<DictModel> texts = commonApi.translateDictFromTableByKeys(table, text, code, values, dataSource);//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------log.debug("translateDictFromTableByKeys.result:" + texts);List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());list.addAll(texts);// 做 redis 缓存for (DictModel dict : texts) {String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue());try {// update-begin-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061// 保留5分钟redisTemplate.opsForValue().set(redisKey, dict.getText(), 300, TimeUnit.SECONDS);// update-end-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061} catch (Exception e) {log.warn(e.getMessage(), e);}}}}//step.3 调用数据库进行翻译普通字典if (needTranslData.size() > 0) {List<String> dictCodeList = Arrays.asList(dataListMap.keySet().toArray(new String[]{}));// 将不包含逗号的字典code筛选出来,因为带逗号的是表字典,而不是普通的数据字典List<String> filterDictCodes = dictCodeList.stream().filter(key -> !key.contains(",")).collect(Collectors.toList());String dictCodes = String.join(",", filterDictCodes);String values = String.join(",", needTranslData);log.debug("translateManyDict.dictCodes:" + dictCodes);log.debug("translateManyDict.values:" + values);Map<String, List<DictModel>> manyDict = commonApi.translateManyDict(dictCodes, values);log.debug("translateManyDict.result:" + manyDict);for (String dictCode : manyDict.keySet()) {List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());List<DictModel> newList = manyDict.get(dictCode);list.addAll(newList);// 做 redis 缓存for (DictModel dict : newList) {String redisKey = String.format("sys:cache:dict::%s:%s", dictCode, dict.getValue());try {redisTemplate.opsForValue().set(redisKey, dict.getText());} catch (Exception e) {log.warn(e.getMessage(), e);}}}}return translText;}/*** 字典值替换文本** @param dictModels* @param values* @return*/private String translDictText(List<DictModel> dictModels, String values) {List<String> result = new ArrayList<>();// 允许多个逗号分隔,允许传数组对象String[] splitVal = values.split(",");for (String val : splitVal) {String dictText = val;for (DictModel dict : dictModels) {if (val.equals(dict.getValue())) {dictText = dict.getText();break;}}result.add(dictText);}return String.join(",", result);}/*** 翻译字典文本* @param code* @param text* @param table* @param key* @return*/@Deprecatedprivate String translateDictValue(String code, String text, String table, String key) {if(oConvertUtils.isEmpty(key)) {return null;}StringBuffer textValue=new StringBuffer();String[] keys = key.split(",");for (String k : keys) {String tmpValue = null;log.debug(" 字典 key : "+ k);if (k.trim().length() == 0) {continue; //跳过循环}//update-begin--Author:scott -- Date:20210531 ----for: !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----if (!StringUtils.isEmpty(table)){log.debug("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code);String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s,%s,%s]",table,text,code,k.trim());if (redisTemplate.hasKey(keyString)){try {tmpValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));} catch (Exception e) {log.warn(e.getMessage());}}else {tmpValue= commonApi.translateDictFromTable(table,text,code,k.trim());}}else {String keyString = String.format("sys:cache:dict::%s:%s",code,k.trim());if (redisTemplate.hasKey(keyString)){try {tmpValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));} catch (Exception e) {log.warn(e.getMessage());}}else {tmpValue = commonApi.translateDict(code, k.trim());}}//update-end--Author:scott -- Date:20210531 ----for: !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----if (tmpValue != null) {if (!"".equals(textValue.toString())) {textValue.append(",");}textValue.append(tmpValue);}}return textValue.toString();}/*** 检测返回结果集中是否包含Dict注解* @param records* @return*/private Boolean checkHasDict(List<Object> records){if(oConvertUtils.isNotEmpty(records) && records.size()>0){for (Field field : oConvertUtils.getAllFields(records.get(0))) {if (oConvertUtils.isNotEmpty(field.getAnnotation(Dict.class))) {return true;}}}return false;}}
package org.jeecg.common.aspect;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.parser.Feature;import com.baomidou.mybatisplus.core.metadata.IPage;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.jeecg.common.api.CommonAPI;import org.jeecg.common.api.vo.Result;import org.jeecg.common.aspect.annotation.Dict;import org.jeecg.common.constant.CommonConstant;import org.jeecg.common.system.vo.DictModel;import org.jeecg.common.util.oConvertUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Lazy;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.time.LocalDate;import java.time.LocalDateTime;import java.util.*;import java.util.concurrent.TimeUnit;import java.util.stream.Collectors;/*** @Description: 字典aop类* @Author: dangzhenghui* @Date: 2019-3-17 21:50* @Version: 1.0*/@Aspect@Component@Slf4jpublic class DictAspect {@Lazy@Autowiredprivate CommonAPI commonApi;@Autowiredpublic RedisTemplate redisTemplate;@Autowiredprivate ObjectMapper objectMapper;private static final String JAVA_UTIL_DATE = "java.util.Date";/*** 定义切点Pointcut*/@Pointcut("(@within(org.springframework.web.bind.annotation.RestController) || " +"@within(org.springframework.stereotype.Controller) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)) " +"&& execution(public org.jeecg.common.api.vo.Result org.jeecg..*.*(..))")public void excudeService() {}@Around("excudeService()")public Object doAround(ProceedingJoinPoint pjp) throws Throwable {long time1=System.currentTimeMillis();Object result = pjp.proceed();long time2=System.currentTimeMillis();log.debug("获取JSON数据 耗时:"+(time2-time1)+"ms");long start=System.currentTimeMillis();result=this.parseDictText(result);long end=System.currentTimeMillis();log.debug("注入字典到JSON数据 耗时"+(end-start)+"ms");return result;}/*** 本方法针对返回对象为Result 的IPage的分页列表数据进行动态字典注入* 字典注入实现 通过对实体类添加注解@dict 来标识需要的字典内容,字典分为单字典code即可 ,table字典 code table text配合使用与原来jeecg的用法相同* 示例为SysUser 字段为sex 添加了注解@Dict(dicCode = "sex") 会在字典服务立马查出来对应的text 然后在请求list的时候将这个字典text,已字段名称加_dictText形式返回到前端* 例输入当前返回值的就会多出一个sex_dictText字段* {* sex:1,* sex_dictText:"男"* }* 前端直接取值sext_dictText在table里面无需再进行前端的字典转换了* customRender:function (text) {* if(text==1){* return "男";* }else if(text==2){* return "女";* }else{* return text;* }* }* 目前vue是这么进行字典渲染到table上的多了就很麻烦了 这个直接在服务端渲染完成前端可以直接用* @param result*//*private Object parseDictText(Object result) {//if (result instanceof Result) {if (true) {if (((Result) result).getResult() instanceof IPage) {List<JSONObject> items = new ArrayList<>();//step.1 筛选出加了 Dict 注解的字段列表List<Field> dictFieldList = new ArrayList<>();// 字典数据列表, key = 字典code,value=数据列表Map<String, List<String>> dataListMap = new HashMap<>(5);//取出结果集List<Object> records=((IPage) ((Result) result).getResult()).getRecords();//update-begin--Author:zyf -- Date:20220606 ----for:【VUEN-1230】 判断是否含有字典注解,没有注解返回-----Boolean hasDict= checkHasDict(records);if(!hasDict){return result;}log.debug(" __ 进入字典翻译切面 DictAspect —— " );//update-end--Author:zyf -- Date:20220606 ----for:【VUEN-1230】 判断是否含有字典注解,没有注解返回-----for (Object record : records) {String json="{}";try {//update-begin--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----//解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormatjson = objectMapper.writeValueAsString(record);//update-end--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----} catch (JsonProcessingException e) {log.error("json解析失败"+e.getMessage(),e);}//update-begin--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);//update-end--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----//update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------//for (Field field : record.getClass().getDeclaredFields()) {// 遍历所有字段,把字典Code取出来,放到 map 里for (Field field : oConvertUtils.getAllFields(record)) {String value = item.getString(field.getName());if (oConvertUtils.isEmpty(value)) {continue;}//update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------if (field.getAnnotation(Dict.class) != null) {if (!dictFieldList.contains(field)) {dictFieldList.add(field);}String code = field.getAnnotation(Dict.class).dicCode();String text = field.getAnnotation(Dict.class).dicText();String table = field.getAnnotation(Dict.class).dictTable();//update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------String dataSource = field.getAnnotation(Dict.class).ds();//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------List<String> dataList;String dictCode = code;if (!StringUtils.isEmpty(table)) {//update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------dictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------}dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(",")));}//date类型默认转换string格式化日期//update-begin--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----//if (JAVA_UTIL_DATE.equals(field.getType().getName())&&field.getAnnotation(JsonFormat.class)==null&&item.get(field.getName())!=null){//SimpleDateFormat aDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));//}//update-end--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----}items.add(item);}//step.2 调用翻译方法,一次性翻译Map<String, List<DictModel>> translText = this.translateAllDict(dataListMap);//step.3 将翻译结果填充到返回结果里for (JSONObject record : items) {for (Field field : dictFieldList) {String code = field.getAnnotation(Dict.class).dicCode();String text = field.getAnnotation(Dict.class).dicText();String table = field.getAnnotation(Dict.class).dictTable();//update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// 自定义的字典表数据源String dataSource = field.getAnnotation(Dict.class).ds();//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------String fieldDictCode = code;if (!StringUtils.isEmpty(table)) {//update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------fieldDictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------}String value = record.getString(field.getName());if (oConvertUtils.isNotEmpty(value)) {List<DictModel> dictModels = translText.get(fieldDictCode);if(dictModels==null || dictModels.size()==0){continue;}String textValue = this.translDictText(dictModels, value);log.debug(" 字典Val : " + textValue);log.debug(" __翻译字典字段__ " + field.getName() + CommonConstant.DICT_TEXT_SUFFIX + ": " + textValue);// TODO-sun 测试输出,待删log.debug(" ---- dictCode: " + fieldDictCode);log.debug(" ---- value: " + value);log.debug(" ----- text: " + textValue);log.debug(" ---- dictModels: " + JSON.toJSONString(dictModels));record.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);}}}((IPage) ((Result) result).getResult()).setRecords(items);}}return result;}*/private Object parseDictText(Object result) {if (result instanceof Result) {Result<?> resultObj = (Result<?>) result;Object data = resultObj.getResult();// 处理IPage类型if (data instanceof IPage) {handleIPage((IPage<?>) data);}// 新增:处理List类型else if (data instanceof List) {handleList((List<?>) data, resultObj);}// 新增:处理单个对象类型else if (data != null) {handleObject(data, resultObj);}}return result;}// 判断是否为简单类型(无需字典处理的类型)private boolean isSimpleType(Class<?> clazz) {return clazz.isPrimitive()|| clazz == String.class|| Number.class.isAssignableFrom(clazz)|| clazz == Boolean.class|| clazz == Date.class|| clazz == LocalDate.class|| clazz == LocalDateTime.class;}private void handleObject(Object data, Result<?> resultObj) {if (data == null) {return;}// 新增:判断是否为简单类型(非对象/非集合),直接跳过if (isSimpleType(data.getClass())) {log.debug("跳过简单类型[{}]的字典处理", data.getClass().getSimpleName());return;}if (data instanceof String) {log.debug("跳过字符串类型结果的字典处理,内容:{}", data.toString().length() > 100 ? data.toString().substring(0, 100) + "..." : data);return;}// 转换对象为JSONObject进行处理JSONObject jsonObject;try {String jsonStr = objectMapper.writeValueAsString(data);log.info("jsonStr:"+jsonStr);// 移除JSON中的控制字符(可选,进一步避免解析错误)jsonStr = jsonStr.replaceAll("[\\x00-\\x1F\\x7F]", "");jsonObject = JSONObject.parseObject(jsonStr, Feature.OrderedField);} catch (JsonProcessingException e) {log.error("对象转JSON失败,跳过字典处理", e);return; // 解析失败时直接返回原始对象,不进行字典处理}// 处理对象中的字典字段List<Field> dictFieldList = new ArrayList<>();Map<String, List<String>> dataListMap = new HashMap<>(5);// 收集对象中所有需要翻译的字典字段for (Field field : oConvertUtils.getAllFields(data)) {String fieldValue = jsonObject.getString(field.getName());if (oConvertUtils.isEmpty(fieldValue)) {continue;}Dict dictAnnotation = field.getAnnotation(Dict.class);if (dictAnnotation != null) {dictFieldList.add(field);// 构建字典codeString code = dictAnnotation.dicCode();String text = dictAnnotation.dicText();String table = dictAnnotation.dictTable();String dataSource = dictAnnotation.ds();String dictCode = code;if (!StringUtils.isEmpty(table)) {dictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);}// 收集需要翻译的值List<String> valueList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());listAddAllDeduplicate(valueList, Arrays.asList(fieldValue.split(",")));}}// 如果没有字典字段,直接返回if (dictFieldList.isEmpty()) {return;}// 批量查询字典值Map<String, List<DictModel>> translText = translateAllDict(dataListMap);// 将字典文本填充到JSONObjectfor (Field field : dictFieldList) {Dict dictAnnotation = field.getAnnotation(Dict.class);String code = dictAnnotation.dicCode();String text = dictAnnotation.dicText();String table = dictAnnotation.dictTable();String dataSource = dictAnnotation.ds();String dictCode = code;if (!StringUtils.isEmpty(table)) {dictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);}String fieldValue = jsonObject.getString(field.getName());if (oConvertUtils.isEmpty(fieldValue)) {continue;}List<DictModel> dictModels = translText.get(dictCode);if (dictModels == null || dictModels.isEmpty()) {continue;}String textValue = translDictText(dictModels, fieldValue);jsonObject.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);}// 将处理后的JSONObject转换回原始对象类型Object processedObject = convertToOriginalType(jsonObject, data.getClass());// 使用反射设置结果try {Method setResultMethod = resultObj.getClass().getMethod("setResult", Object.class);setResultMethod.invoke(resultObj, processedObject);} catch (Exception e) {log.error("设置结果失败", e);}}/*** 将JSONObject转换为原始对象类型*/private Object convertToOriginalType(JSONObject jsonObject, Class<?> originalType) {try {return objectMapper.treeToValue(objectMapper.readTree(jsonObject.toJSONString()), originalType);} catch (JsonProcessingException e) {log.error("转换回原始类型失败", e);return jsonObject; // 转换失败时返回JSONObject}}/*** 处理记录列表(支持IPage的records和普通List)*/private List<JSONObject> processRecords(List<?> records) {// 步骤1:检查是否包含@Dict注解字段,无则直接返回Boolean hasDict = checkHasDict(records);if (!hasDict) {return records.stream().map(record -> {try {// return JSONObject.parseObject(objectMapper.writeValueAsString(record), Feature.OrderedField);String jsonStr;// 对字符串类型直接处理,避免额外引号if (record instanceof String) {String str = (String) record;// 移除控制字符str = str.replaceAll("[\\x00-\\x1F\\x7F]", "");// 包装为JSON对象(键为"value",值为处理后的字符串)JSONObject json = new JSONObject();json.put("value", str);return json;} else {// 非字符串类型正常转换并移除控制字符jsonStr = objectMapper.writeValueAsString(record);jsonStr = jsonStr.replaceAll("[\\x00-\\x1F\\x7F]", "");return JSONObject.parseObject(jsonStr, Feature.OrderedField);}} catch (JsonProcessingException e) {log.error("对象转JSON失败", e);return new JSONObject();}}).collect(Collectors.toList());}log.debug("__ 进入字典翻译切面(处理List/IPage) __");// 步骤2:收集需要翻译的字典信息List<JSONObject> items = new ArrayList<>();List<Field> dictFieldList = new ArrayList<>(); // 含@Dict注解的字段Map<String, List<String>> dataListMap = new HashMap<>(5); // key:字典code,value:需要翻译的字段值列表for (Object record : records) {// 将对象转为有序JSONObject(保持字段顺序)String json;try {json = objectMapper.writeValueAsString(record);} catch (JsonProcessingException e) {log.error("json解析失败", e);continue;}JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);// 遍历所有字段(含父类字段),收集字典信息for (Field field : oConvertUtils.getAllFields(record)) {String fieldValue = item.getString(field.getName());if (oConvertUtils.isEmpty(fieldValue)) {continue;}Dict dictAnnotation = field.getAnnotation(Dict.class);if (dictAnnotation != null) {// 收集含@Dict注解的字段if (!dictFieldList.contains(field)) {dictFieldList.add(field);}// 构建字典code(区分普通字典和表字典)String code = dictAnnotation.dicCode();String text = dictAnnotation.dicText();String table = dictAnnotation.dictTable();String dataSource = dictAnnotation.ds(); // 数据源(分布式场景)String dictCode = code;if (!StringUtils.isEmpty(table)) {dictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);}// 收集该字典code对应的所有需要翻译的值(去重)List<String> valueList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());List<String> splitValues = Arrays.stream(fieldValue.split(",")).map(String::trim).filter(v -> !v.isEmpty()).collect(Collectors.toList());listAddAllDeduplicate(valueList, splitValues);}}items.add(item);}// 步骤3:批量查询所有字典值(复用现有逻辑)Map<String, List<DictModel>> translText = translateAllDict(dataListMap);// 步骤4:将字典文本填充到结果中(添加xxx_dictText字段)for (JSONObject item : items) {for (Field field : dictFieldList) {Dict dictAnnotation = field.getAnnotation(Dict.class);String code = dictAnnotation.dicCode();String text = dictAnnotation.dicText();String table = dictAnnotation.dictTable();String dataSource = dictAnnotation.ds();String dictCode = code;if (!StringUtils.isEmpty(table)) {dictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);}String fieldValue = item.getString(field.getName());if (oConvertUtils.isEmpty(fieldValue)) {continue;}// 从翻译结果中获取文本List<DictModel> dictModels = translText.get(dictCode);if (dictModels == null || dictModels.isEmpty()) {continue;}String textValue = translDictText(dictModels, fieldValue);// 添加xxx_dictText字段item.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);}}return items;}/*** 处理IPage类型结果*//*** 处理IPage类型结果*/private void handleIPage(IPage<?> page) {List<?> records = page.getRecords();if (oConvertUtils.isEmpty(records)) {return;}// 处理记录并获取JSONObject列表List<JSONObject> processedRecords = processRecords(records);// 如果列表不为空,尝试转换回原始类型if (!processedRecords.isEmpty() && records.size() > 0) {Class<?> originalType = records.get(0).getClass();List<Object> convertedRecords = processedRecords.stream().map(json -> {try {// 将JSONObject转换回原始对象类型return objectMapper.treeToValue(objectMapper.readTree(json.toJSONString()), originalType);} catch (JsonProcessingException e) {log.error("转换JSONObject回原始类型失败", e);return json; // 转换失败时保留JSONObject}}).collect(Collectors.toList());// 使用反射调用setRecords方法(绕过泛型检查)try {Method setRecordsMethod = page.getClass().getMethod("setRecords", List.class);setRecordsMethod.invoke(page, processedRecords);} catch (Exception e) {log.error("调用setRecords方法失败", e);}}}/*** 处理List类型结果*/private void handleList(List<?> records, Result<?> resultObj) {if (oConvertUtils.isEmpty(records)) {return;}// 转换为List<Object>(避免泛型问题)List<Object> recordList = records.stream().map(r -> (Object) r).collect(Collectors.toList());List<JSONObject> processedRecords = processRecords(recordList);// 使用反射设置结果,绕过泛型检查try {Method setResultMethod = resultObj.getClass().getMethod("setResult", Object.class);setResultMethod.invoke(resultObj, processedRecords);} catch (Exception e) {log.error("设置结果失败", e);}}/*** list 去重添加*/private void listAddAllDeduplicate(List<String> dataList, List<String> addList) {// 筛选出dataList中没有的数据List<String> filterList = addList.stream().filter(i -> !dataList.contains(i)).collect(Collectors.toList());dataList.addAll(filterList);}/*** 一次性把所有的字典都翻译了* 1. 所有的普通数据字典的所有数据只执行一次SQL* 2. 表字典相同的所有数据只执行一次SQL* @param dataListMap* @return*/private Map<String, List<DictModel>> translateAllDict(Map<String, List<String>> dataListMap) {// 翻译后的字典文本,key=dictCodeMap<String, List<DictModel>> translText = new HashMap<>(5);// 需要翻译的数据(有些可以从redis缓存中获取,就不走数据库查询)List<String> needTranslData = new ArrayList<>();//step.1 先通过redis中获取缓存字典数据for (String dictCode : dataListMap.keySet()) {List<String> dataList = dataListMap.get(dictCode);if (dataList.size() == 0) {continue;}// 表字典需要翻译的数据List<String> needTranslDataTable = new ArrayList<>();for (String s : dataList) {String data = s.trim();if (data.length() == 0) {continue; //跳过循环}if (dictCode.contains(",")) {String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, data);if (redisTemplate.hasKey(keyString)) {try {String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());list.add(new DictModel(data, text));} catch (Exception e) {log.warn(e.getMessage());}} else if (!needTranslDataTable.contains(data)) {// 去重添加needTranslDataTable.add(data);}} else {String keyString = String.format("sys:cache:dict::%s:%s", dictCode, data);if (redisTemplate.hasKey(keyString)) {try {String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());list.add(new DictModel(data, text));} catch (Exception e) {log.warn(e.getMessage());}} else if (!needTranslData.contains(data)) {// 去重添加needTranslData.add(data);}}}//step.2 调用数据库翻译表字典if (needTranslDataTable.size() > 0) {String[] arr = dictCode.split(",");String table = arr[0], text = arr[1], code = arr[2];String values = String.join(",", needTranslDataTable);//update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------// 自定义的数据源String dataSource = null;if (arr.length > 3) {dataSource = arr[3];}//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------log.debug("translateDictFromTableByKeys.dictCode:" + dictCode);log.debug("translateDictFromTableByKeys.values:" + values);//update-begin---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------//update-begin---author:wangshuai---date:2024-01-09---for:微服务下为空报错没有参数需要传递空字符串---if(null == dataSource){dataSource = "";}//update-end---author:wangshuai---date:2024-01-09---for:微服务下为空报错没有参数需要传递空字符串---List<DictModel> texts = commonApi.translateDictFromTableByKeys(table, text, code, values, dataSource);//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------log.debug("translateDictFromTableByKeys.result:" + texts);List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());list.addAll(texts);// 做 redis 缓存for (DictModel dict : texts) {String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue());try {// update-begin-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061// 保留5分钟redisTemplate.opsForValue().set(redisKey, dict.getText(), 300, TimeUnit.SECONDS);// update-end-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061} catch (Exception e) {log.warn(e.getMessage(), e);}}}}//step.3 调用数据库进行翻译普通字典if (needTranslData.size() > 0) {List<String> dictCodeList = Arrays.asList(dataListMap.keySet().toArray(new String[]{}));// 将不包含逗号的字典code筛选出来,因为带逗号的是表字典,而不是普通的数据字典List<String> filterDictCodes = dictCodeList.stream().filter(key -> !key.contains(",")).collect(Collectors.toList());String dictCodes = String.join(",", filterDictCodes);String values = String.join(",", needTranslData);log.debug("translateManyDict.dictCodes:" + dictCodes);log.debug("translateManyDict.values:" + values);Map<String, List<DictModel>> manyDict = commonApi.translateManyDict(dictCodes, values);log.debug("translateManyDict.result:" + manyDict);for (String dictCode : manyDict.keySet()) {List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());List<DictModel> newList = manyDict.get(dictCode);list.addAll(newList);// 做 redis 缓存for (DictModel dict : newList) {String redisKey = String.format("sys:cache:dict::%s:%s", dictCode, dict.getValue());try {redisTemplate.opsForValue().set(redisKey, dict.getText());} catch (Exception e) {log.warn(e.getMessage(), e);}}}}return translText;}/*** 字典值替换文本** @param dictModels* @param values* @return*/private String translDictText(List<DictModel> dictModels, String values) {List<String> result = new ArrayList<>();// 允许多个逗号分隔,允许传数组对象String[] splitVal = values.split(",");for (String val : splitVal) {String dictText = val;for (DictModel dict : dictModels) {if (val.equals(dict.getValue())) {dictText = dict.getText();break;}}result.add(dictText);}return String.join(",", result);}/*** 翻译字典文本* @param code* @param text* @param table* @param key* @return*/@Deprecatedprivate String translateDictValue(String code, String text, String table, String key) {if(oConvertUtils.isEmpty(key)) {return null;}StringBuffer textValue=new StringBuffer();String[] keys = key.split(",");for (String k : keys) {String tmpValue = null;log.debug(" 字典 key : "+ k);if (k.trim().length() == 0) {continue; //跳过循环}//update-begin--Author:scott -- Date:20210531 ----for: !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----if (!StringUtils.isEmpty(table)){log.debug("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code);String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s,%s,%s]",table,text,code,k.trim());if (redisTemplate.hasKey(keyString)){try {tmpValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));} catch (Exception e) {log.warn(e.getMessage());}}else {tmpValue= commonApi.translateDictFromTable(table,text,code,k.trim());}}else {String keyString = String.format("sys:cache:dict::%s:%s",code,k.trim());if (redisTemplate.hasKey(keyString)){try {tmpValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));} catch (Exception e) {log.warn(e.getMessage());}}else {tmpValue = commonApi.translateDict(code, k.trim());}}//update-end--Author:scott -- Date:20210531 ----for: !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----if (tmpValue != null) {if (!"".equals(textValue.toString())) {textValue.append(",");}textValue.append(tmpValue);}}return textValue.toString();}/*** 检测返回结果集中是否包含Dict注解* @param records* @return*/private Boolean checkHasDict(List<?> records){if(oConvertUtils.isNotEmpty(records) && records.size()>0){for (Field field : oConvertUtils.getAllFields(records.get(0))) {if (oConvertUtils.isNotEmpty(field.getAnnotation(Dict.class))) {return true;}}}return false;}}