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

字典切面实现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 "";
}

切入点作用于实现类重写的方法上即可,如:
在这里插入图片描述
如:某实体类的字段上加入注解标识父级code和当前code即可得到该accountStatus字段对应的字典值
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值