后端实习产出--通过自定义注解、反射、进行切面编程实现一个转化工具

前置知识:

需要会自定义注解方法自定义注解字段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指定的字段上的字典编码转换为字典值。下面我逐行解析这个方法是如何实现的。

  1. 第一行的方法签名 private void convertData(Object o, Map<String, Map<String, String>> map) 中,参数 o 是需要进行字典编码转换的 Java 对象,参数 map 是存储字典数据的双重映射表。

  2. 第二行判断对象是否为空,如果为空则直接返回。

  3. 第三行获取对象的类类型,并遍历该类及其父类上的所有成员变量。

  4. 第四行获取当前成员变量的类型,并设置该成员变量可访问。

  5. 第五行判断当前成员变量的类型是否为自定义类型,如List等。如果是自定义类型,则递归调用 convertData 方法,继续进行字典编码转换。

  6. 第九行判断当前成员变量上是否存在 IntdDict 注解,如果不存在则继续遍历下一个成员变量。

  7. 第十行调用 getTypeCode 方法获取该成员变量的字典类型编码。

  8. 第十二到第二十七行,根据成员变量的字典类型编码和字典编码,从 map 中获取相应的字典值并设置回成员变量上。如果 map 中没有包含该字典类型,则调用 DictUtil 类获取该字典类型的字典数据,并将其存储到 map 中。

  9. 最后一行结束方法的执行。

总体来说,这段代码实现了一个自动化的 Java 对象转换工具,能够快速地将对象中的字典编码转换为相应的字典值,大大简化了对字典数据的操作。它的主要思路是通过反射获取对象属性上的注解信息,然后通过该注解信息获取需要进行转换的字典编码和字典类型,最后从预先加载到内存中的 map 表中获取相应的字典值并设置回属性中。该代码通过提高字典数据的查询效率和方便性,大大提高了开发效率并优化了程序性能。

优点:这个工具类被我封装为了一个starter,有微服务模块都能引用我这个代码,实现低耦合,开发过程只需要引用我这个自定义注解即可实现功能。且前端开发也无需自己处理这类数据,直接获取展示到界面就可以。无需在前端为每个数据字典类型编写相应的转码逻辑,减少了前端的代码量,同时也便于后端代码的复用。此外,由于注解可以作用于所有需要进行数据字典转码的方法上,因此也可以提高项目的代码一致性。

缺点:这个递归写的不是很完美,途中出过bug,调试了很久发现不能在实体类上用这个注解@Slf4j不然递归会很深导致栈溢出,需要继续完善,测试。在进行AOP注解拦截时,需要通过反射来获取被注解方法的参数并进行数据字典转码。这个过程需要额外的时间和计算资源,可能会对应用服务的性能产生一定的影响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值