一、需求描述:
某一字段在数据库中存储的为数值,而在返回前端时想将它转换为对应的文字,从而不需要前端去维护。
这是在字典表里面具体代表的文字,1代表推送成功,0代表推送失败。
二、解决方案:
1、编写方法注解DictCovert
作用于controller方法上,用于获取返回的数据
import java.lang.annotation.*;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictCovert {
}
2、编写字段注解Dict
作业于需要转换的字段上,用于后续找到该需要转换的字段
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Dict {
/**
* 字典类型名称
*/
String dictTypeName() default "";
/**
* 字典存放后缀
* 默认 "Text"
* 例 原始字段名:type 翻译储存的字段名:typeText
**/
String suffix() default "Text";
}
3、编写字典转换工具类DictUtil
DictUtil自行适当修改
import cn.hutool.core.util.ObjectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class DictUtil {
/**
* 使用个缓存,避免列表数据多次进行字典查询
*/
private static ThreadLocal<Map<String,Map<String,String>>> cache = ThreadLocal.withInitial(ConcurrentHashMap::new);
//mapper查询数据库,查询字典数字对应的文字
@Autowired
private DictionariesItemMapper dictionariesItemMapper;
private static DictUtil dictUtil;
@PostConstruct
public void init() {
dictUtil = this;
dictUtil.dictionariesItemMapper = this.dictionariesItemMapper;
}
public static Object parseResult(Object result) throws Exception {
//判断空
if (Objects.isNull(result)) {
return null;
}
//判断结果类型
if (result instanceof List) {
//LIST类型
List<Object> list = Lists.newArrayList();
for (Object obj : (List<Object>) result) {
list.add(parseDict(obj));
}
return list;
} else if (result instanceof TableDataInfo) {
//自定义的分页返回结果集类型 实际结果在 list字段中。 处理和LIST一致
TableDataInfo tableDataInfo = (TableDataInfo) result;
List<Object> list = Lists.newArrayList();
for (Object obj : tableDataInfo.getRows()) {
list.add(parseDict(obj));
}
//分页数据中 重新放入结果
tableDataInfo.setRows(list);
return tableDataInfo;
} else if (result instanceof AjaxResult){
//自定义的返回结果集类型 实际结果在 data字段中。 处理和LIST一致
AjaxResult ajaxResult = (AjaxResult) result;
Object data = ajaxResult.get("data");
return AjaxResult.success(parseDict(data));
} else {
//单实例对象
return parseDict(result);
}
//.....根据自己的需求判断相应的类型
}
/**
* 字典转换
*
* @param obj
*/
private static Object parseDict(Object obj) throws NoSuchFieldException, IllegalAccessException {
Field[] fields = obj.getClass().getDeclaredFields();
//非空判断
if (ObjectUtil.isEmpty(fields)) {
return null;
}
for (Field field : fields) {
//判断每一个字典是否有Dict注解
if (Objects.nonNull(field.getAnnotation(Dict.class))) {
handleDict(obj, field);
}
}
return obj;
}
/**
* 处理字典注解的字段
*
* @param obj
* @param field
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static void handleDict(Object obj, Field field) throws NoSuchFieldException, IllegalAccessException {
Dict dict = field.getAnnotation(Dict.class);
String dictTypeName = dict.dictTypeName();
String suffix = dict.suffix();
Map<String, String> dictitemValMap = getDictmap(dictTypeName);
Field name = obj.getClass().getDeclaredField(field.getName() + suffix);
field.setAccessible(true);
Object key = field.get(obj);
name.setAccessible(true);
name.set(obj, dictitemValMap.get(key.toString()));
name.setAccessible(false);
field.setAccessible(false);
}
private static Map<String, String> getDictmap(String dictTypeName) {
Map<String, Map<String, String>> dictMap = cache.get();
if(dictMap.containsKey(dictTypeName)){
return dictMap.get(dictTypeName);
}
List<DictionariesItem> dictionariesItemList = dictUtil.dictionariesItemMapper.getDictionariesItemMap(dictTypeName);
Map<String, String> dictItemMap = new HashMap<>();
if (CollectionUtils.isEmpty(dictionariesItemList)) {
return dictItemMap;
}
for (DictionariesItem dictionariesItem : dictionariesItemList) {
dictItemMap.put(dictionariesItem.getItemValue(), dictionariesItem.getItemName());
}
dictMap.put(dictTypeName,dictItemMap);
cache.set(dictMap);
return dictItemMap;
}
/**
* 清除缓存
*/
public static void clearCache(){
cache.remove();
}
}
4、编写AOP类DictAspect
import com.jl.pfs.utils.DictUtil;
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.springframework.context.annotation.Configuration;
@Aspect
@Configuration
public class DictAspect {
@Pointcut("@annotation(com.jl.pfs.aop.dict.DictCovert)")
public void dictCovert() {
}
@Around("dictCovert()")
public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
//1.执行原方法
Object proceed = joinPoint.proceed();
//2.拿到原方法的原返回值 调用parseResult进行字典转换
Object result = DictUtil.parseResult(proceed);
DictUtil.clearCache();
return result;
}
}
5、将相应的注解放在相应的地方
@DictCovert作用于Controller上
@Dict作用于属性上
三、实现效果:
统一实现返回时增加的字段显示对应的文字,当字典修改时,返回的文字也会跟着修改