前置知识:
需要会自定义注解方法自定义注解字段AOP切面编程,反射等...
核心代码结构:

核心代码实现:
package com.***.config;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.***.common.entity.dto.PageResult;
import com.***.common.utils.R;
import com.***.util.DictUtil;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@Component
@Aspect
public class IntdDictMethodAop {
    @SneakyThrows
    @Around("@annotation(IntdDictMethod)")
    public Object around(ProceedingJoinPoint pjp) {
        Object proceed = pjp.proceed();
        Map<String, Map<String, String>> map = Maps.newHashMap();
        if (proceed instanceof R) {
            Object data = objParse(R.class, proceed).getData();
            if (data != null) {
                if (data.getClass().isArray() || data instanceof Collection) {
                    Collection<Object> collections = listParse(Object.class, data);
                    //如果返回数据是数组或集合,则遍历其中的每个元素并调用 convertData 方法进行转换
                    for (Object datum : collections) {
                        convertData(datum, map);
                    }
                } else if (data instanceof PageResult) {
                    Collection<Object> innerData = listParse(Object.class, objParse(PageResult.class, data).getData());
                    for (Object obj : innerData) {
                        convertData(obj, map);
                    }
                } else {
                    convertData(data, map);
                }
            }
        } else if (proceed instanceof PageResult) {
            Collection<Object> innerData = listParse(Object.class, objParse(PageResult.class, proceed).getData());
            for (Object obj : innerData) {
                convertData(obj, map);
            }
        } else if (proceed instanceof Collection) {
            Collection<Object> collections = listParse(Object.class, proceed);
            for (Object datum : collections) {
                convertData(datum, map);
            }
        } else {
            convertData(proceed, map);
        }
        return proceed;
    }
    public static <T> T objParse(Class<T> clazz, Object value) {
        return clazz.cast(value);
    }
    public static <T> Collection<T> listParse(Class<T> clazz, Object obj) {
        if (obj == null) {
            return new ArrayList<>();
        }
        Collection<T> result = new ArrayList<>();
        for (Object o : (Collection<?>) obj) {
            result.add(clazz.cast(o));
        }
        return result;
    }
    @SneakyThrows
    private void convertData(Object o, Map<String, Map<String, String>> map) {
        if (o == null) {
            return;
        }
        Class<?> sourceClass = o.getClass();
        for (; sourceClass != Object.class; sourceClass = sourceClass.getSuperclass()) {
            Field[] fields = sourceClass.getDeclaredFields();
            for (Field field : fields) {
                Class<?> type = field.getType();
                field.setAccessible(true);
                if (type.getClassLoader()!=null) {
                    Object o1 = field.get(o);
                    convertData(o1,map);
                    continue;
                }
                if (List.class.isAssignableFrom(type)) {
                    List fieldListObj = (List) field.get(o);
                    if (fieldListObj != null && fieldListObj.size() > 0) {
                        for (int i = 0; i < fieldListObj.size(); i++) {
                            Object o1 = fieldListObj.get(i);
                            if (o1 != null) {
                                if (o1.getClass().getClassLoader() != null) {
                                    convertData(o1,map);
                                }
                            }
                        }
                    }
                    continue;
                }
                IntdDict intdDict = field.getAnnotation(IntdDict.class);
                if (intdDict == null) {
                    continue;
                }
                String typeCode = getTypeCode(intdDict, sourceClass, o);
                if (StrUtil.isEmpty(typeCode)) {
                    continue;
                }
                String dictCodeField = crmDict.dictCodeField();
                Field declaredField = sourceClass.getDeclaredField(dictCodeField);
                declaredField.setAccessible(true);
                String dictCode = null;
                if (declaredField.getType().equals(String.class)) {
                    dictCode = (String) declaredField.get(o);
                }
                if(declaredField.getType().equals(Integer.class)){
                    dictCode = declaredField.get(o)!=null ? declaredField.get(o).toString() : null;
                }
                if (StrUtil.isEmpty(dictCode)) {
                    continue;
                }
                Map<String, String> dictTypeMap = map.get(typeCode);
                if (dictTypeMap != null) {
                    String val = dictTypeMap.get(dictCode);
                    if (!StrUtil.isEmpty(val)) {
                        field.set(o, val);
                    }
                } else {
                    DictUtil dictUtil=new DictUtil();
                    Map<String, String> dictMap = dictUtil.dictMap(typeCode);
                    if (dictMap != null) {
                        map.put(typeCode, dictMap);
                        String val = dictMap.get(dictCode);
                        if (!StrUtil.isEmpty(val)) {
                            field.set(o, val);
                        }
                    }
                }
            }
        }
    }
    @SneakyThrows
    private String getTypeCode(IntdDict intdDict, Class<?> sourceClass, Object o) {
        String type = intdDict.type();
        if ("1".equals(type)) {
            return intdDict.typeCode();
        } else if ("2".equals(type)) {
            String typeCode = intdDict.typeCode();
            Field typeCodeField = sourceClass.getDeclaredField(typeCode);
            typeCodeField.setAccessible(true);
            return (String) typeCodeField.get(o);
        }
        return null;
    }
}
 
核心代码是一个数据转换操作的方法,主要作用是将 Java 对象中被自定义注解@IntdDict指定的字段上的字典编码转换为字典值。下面我逐行解析这个方法是如何实现的。
-  
第一行的方法签名
private void convertData(Object o, Map<String, Map<String, String>> map)中,参数o是需要进行字典编码转换的 Java 对象,参数map是存储字典数据的双重映射表。 -  
第二行判断对象是否为空,如果为空则直接返回。
 -  
第三行获取对象的类类型,并遍历该类及其父类上的所有成员变量。
 -  
第四行获取当前成员变量的类型,并设置该成员变量可访问。
 -  
第五行判断当前成员变量的类型是否为自定义类型,如List等。如果是自定义类型,则递归调用
convertData方法,继续进行字典编码转换。 -  
第九行判断当前成员变量上是否存在
IntdDict注解,如果不存在则继续遍历下一个成员变量。 -  
第十行调用
getTypeCode方法获取该成员变量的字典类型编码。 -  
第十二到第二十七行,根据成员变量的字典类型编码和字典编码,从
map中获取相应的字典值并设置回成员变量上。如果map中没有包含该字典类型,则调用DictUtil类获取该字典类型的字典数据,并将其存储到map中。 -  
最后一行结束方法的执行。
 
总体来说,这段代码实现了一个自动化的 Java 对象转换工具,能够快速地将对象中的字典编码转换为相应的字典值,大大简化了对字典数据的操作。它的主要思路是通过反射获取对象属性上的注解信息,然后通过该注解信息获取需要进行转换的字典编码和字典类型,最后从预先加载到内存中的 map 表中获取相应的字典值并设置回属性中。该代码通过提高字典数据的查询效率和方便性,大大提高了开发效率并优化了程序性能。
优点:这个工具类被我封装为了一个starter,有微服务模块都能引用我这个代码,实现低耦合,开发过程只需要引用我这个自定义注解即可实现功能。且前端开发也无需自己处理这类数据,直接获取展示到界面就可以。
缺点:这个递归写的不是很完美,途中出过bug,调试了很久发现不能在实体类上用这个注解@Slf4j不然递归会很深导致栈溢出,需要继续完善,测试。



















