欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring boot + aop切面+反射-实现数据字典匹配

程序员文章站 2022-10-04 09:14:26
字典切面实现package com.cxm.wechat.common.aop;import com.alibaba.fastjson.JSON;import com.cxm.common.annotation.DictInfoAnnotation;import com.cxm.common.exception.BusinessException;import com.cxm.commons.constants.Constants;import com.cxm.commons.utils.Da...
字典切面实现code动态匹配字典表返回对应的值,解决需要关联查询字典表的问题,可以进一步优化sql执行效率,里面主要整合了 实体,List,项目响应消息实体的字典数据组装。
主要代码如下:
package com.cxm.wechat.common.aop;

import com.alibaba.fastjson.JSON;
import com.cxm.common.annotation.DictInfoAnnotation;
import com.cxm.common.exception.BusinessException;
import com.cxm.commons.constants.Constants;
import com.cxm.commons.utils.DateUtil;
import com.cxm.wechat.service.IDictInfoService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.log4j.Log4j2;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 字典切面实现类
 * @author zhangliuming
 * @date 2019/4/28
 */
@Aspect
@Component
@Log4j2
public class DictInfoAspect {
    @Resource
    private IDictInfoService dictInfoService;

    /**
     * 根据改注解实现切点
     */
    @Pointcut("@annotation(com.cxm.common.annotation.DictUtilAnnotation)")
    public void logPointCut() {
    }

    /**
     * @decription  环绕通知,包围一个连接点的通知
     * @author zhangliuming
     * @date 2019/4/30
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // 执行方法获取返回的结果
        Object result = point.proceed();
        if (result == null){
            return null;
        }
        Class<?> classInfo = null;
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) point.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        // 获取返回值类型
        Type type = method.getGenericReturnType();
        // 判断获取的类型是否是参数类型
        if (type instanceof ParameterizedType) {
            // 强制转型为带参数的泛型类型,
            Type[] typesto = ((ParameterizedType) type).getActualTypeArguments();
            List lists = new ArrayList();
            classInfo = Class.forName(typesto[0].getTypeName());
            //如果类型为list对象就对其做list数据转换
            JSONArray jsonArray = null;
            if (((ParameterizedType) type).getRawType().getTypeName().equals(Constants.DataType.JAVA_UTIL_LIST)){
                jsonArray = JSONArray.parseArray(JSON.toJSONString(result));
                if (jsonArray != null){
                    //获取list对象
                    for (int i = 0; i < jsonArray.size(); i++) {
                        jsonArray.set(i,fieldToValue(classInfo, jsonArray.getJSONObject(i)));
                    }
                    result = jsonArrayToListBean(jsonArray, classInfo);
                }
            } else {
                //数据转json
                JSONObject jsonResult = JSONObject.parseObject(JSON.toJSONString(result));
                List list = (List) jsonResult.get("data");
                for (int i = 0; i < list.size(); i++) {
                    lists.add(fieldToValue(classInfo, (JSONObject) list.get(i)));
                }
                jsonResult.put("data", lists);
                result = jsonObjToClass(jsonResult, result.getClass());
            }
        }else {
            classInfo = result.getClass();
            JSONObject jsonResult = JSONObject.parseObject(JSON.toJSONString(result));
            Object obj=fieldToValue(classInfo, jsonResult);
            //map数据转为原始对象
            JSONObject objs = JSONObject.parseObject(JSON.toJSONString(obj));
            result = jsonObjToClass(objs, classInfo);
        }
        long time = System.currentTimeMillis() - beginTime;
        log.info("总耗时:" + time);
        // 保存日志
        return result;
    }

    /**
     * @description 给注解的字段赋值
     * @author zhangliuming
     * @date 2019/4/29
     * @param c
     * @param jsonObject
     * @return
     */
    public Object fieldToValue(Class<?> c, JSONObject jsonObject) {
        Field[] field = c.getDeclaredFields();
        for (Field f : field) {
            DictInfoAnnotation fa = f.getAnnotation(DictInfoAnnotation.class);
            //判断是否是加入注解的字段,是给其赋值
            if (fa != null) {
                try {
                    String name = f.getName();
                    String dictCode = String.valueOf(jsonObject.get(name));
                    if (StringUtils.isEmpty(dictCode)){
                        jsonObject.put(name, "");
                    }else {
                        //根据字典父级编码和code取该字典值
                        String value = dictInfoService.getValueByParentIdAndCode(fa.parentId(), dictCode);
                        jsonObject.put(name, value);
                    }
                } catch (BusinessException e){
                    log.error(e.getErrorMsg());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return jsonObject;
    }

    /**
     * @description jsonObj转为传入的Class对象------反射原理
     * @author zhangliuming
     * @date 2019/4/30
     * @param jsonObject
     * @param clz
     * @return
     * @throws Exception
     */
    public Object jsonObjToClass(JSONObject jsonObject, Class<?> clz) throws Exception {
        Object obj = clz.newInstance();
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            field.setAccessible(true);
            String filedTypeName = field.getType().getName();
            //日期字段类型需要单独处理
            if (filedTypeName.equalsIgnoreCase(Constants.DataType.LOCAL_DATE_TIME)) {
                String value = (String) jsonObject.get(field.getName());
                if (value == null){
                    field.set(obj, null);
                }else {
                    field.set(obj, DateUtil.str2LocalDateTime(value));
                }
            } else if(filedTypeName.equalsIgnoreCase(Constants.DataType.LOCAL_DATE)){
                String value = (String) jsonObject.get(field.getName());
                if (value == null){
                    field.set(obj, null);
                }else {
                    field.set(obj, DateUtil.str2LocalDate(value));
                }
            } else if(filedTypeName.equalsIgnoreCase(Constants.DataType.JAVA_UTIL_DATE)){
                String value = (String) jsonObject.get(field.getName());
                if (value == null){
                    field.set(obj, null);
                }else {
                    field.set(obj, DateUtil.str2Date(value,DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS));
                }
            }else {
                field.set(obj, jsonObject.get(field.getName()));
            }
        }
        return obj;
    }


    /**
     *
     * @description 将jsonArray转换为JavaBean的方法
     * @date 2019/4/30
     * @author zhangliuming
     * @param jsonArray
     * @param clz
     * @return
     * @throws Exception
     */
    public JSONArray jsonArrayToListBean(JSONArray jsonArray,Class<?> clz )throws Exception {
        JSONArray jsonArray1 = new JSONArray();
        // 将jsonArray转换为JavaBean的方法
        for (int i = 0; i < jsonArray.size(); i++) {
            Object objs = jsonObjToClass(jsonArray.getJSONObject(i), clz);
            // 添加进list集合
            jsonArray1.add(objs);
        }
        return jsonArray1;
    }
}

package com.cxm.common.annotation;
import org.springframework.core.annotation.Order;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @description 字典工具主要用于实现方法级别的切点
 * @author zhangliuming
 * @date 2019/4/28
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Order(value = -100)//这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高
public @interface DictUtilAnnotation {

}

package com.cxm.common.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @description 字典信息自定义注解,标记再需要转换的实体字典列上
 * @author zhangliuming
 * @date 2019/4/28
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DictInfoAnnotation {
    String parentId() default "";
}

切入点作用于实现类重写的方法上即可,如:
spring boot + aop切面+反射-实现数据字典匹配
如:某实体类的字段上加入注解标识父级code和当前code即可得到该accountStatus字段对应的字典值
spring boot + aop切面+反射-实现数据字典匹配

本文地址:https://blog.csdn.net/qq13142243114/article/details/107338276