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

aop+反射:日志切面(获取list及其他类型值)

程序员文章站 2022-09-16 21:09:19
#1)作用 1. 获取方法的某个参数的属性的值(返回值类型不确定,需要的参数在对象中位置不确定)#2)举例需求:记录操作日志,保存用户删除订单、购买物品等操作2.1:注解/*** 保存记录开关* @Auther: ZhangSuchao* @Date: 2020/7/29 21:...

1:作用

       1. 获取方法的某个参数的属性的值(返回值类型不确定,需要的参数在对象中位置不确定)

2:举例

        需求:记录操作日志,保存用户删除订单、购买物品等操作

    2.1:注解

/**
* 保存记录开关
* @Auther: ZhangSuchao
* @Date: 2020/7/29 21:02
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SaveLog {

  // 获取的订单(物品)的id集合
  String idsName() default "";

  // 操作类型
  int operatorKind() default 0;

  // 操作理由(可以记录一些删除原因,驳回原因)
  String remarkName() default "";
}

    2.2:请求实体类

import lombok.Data;

/**
* @Auther: ZhangSuchao
* @Date: 2020/7/29 20:02
*/
@Data
public class OrderDTO {

   // 订单s
   private Integer ids;

   // 原因
   private String remark;
}

    2.3:Service方法

    /**
     * 删除订单
     *
     * @param orderDTO
     */
    @SaveLog(idsName = "orderDTO-ids", remarkName = "orderDTO-remark", operatorKind = 1)
    public void delOrders(OrderDTO orderDTO) {

        // TODO: 2020/7/29 删除订单操作
    }
    /**
     * 购买物品
     *
     * @param orderId 订单id
     */
    @SaveLog(idsName = "orderId", operatorKind = 2)
    public void buyGoods(Integer orderId) {
        // TODO: 2020/7/29 购买物品
    }

    2.4:目的

获取2.3中 delOrders 方法的 ids与 remark,也要获取 buyGoods 中的 orderId

3: 切面

/**
 * 日志切面
 *
 * @Auther: ZhangSuchao
 * @Date: 2020/7/29 19:38
 */
@Aspect
@Component
public class LogAspect {

    @Pointcut(value = "@annotation(com.draymond.aop.annotation.SaveLog)")
    public void logPoint() {

    }

    @AfterReturning(value = "logPoint()")
    public void saveLog(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SaveLog saveLog = method.getAnnotation(SaveLog.class);
        if (saveLog == null) {
            return;
        }
        // 获取参数名称
        String[] paraNames = signature.getParameterNames();
        // 参数的值
        Object[] paraValues = joinPoint.getArgs();

        // 警告:idsName对应的值可能为Integer,也可能为List<Integer>
        String idsName = saveLog.idsName();
        int operatorKind = saveLog.operatorKind();
        String remarkName = saveLog.remarkName();

        // 获取到了Integer/List<Integer> 备注:如果 idsName 只表示一种类型,也可以用具体的类型接收(泛型的强大之处)
        Object object = ReflectUtils.getValueByParaName(idsName, paraNames, paraValues);

        // 获取到了String
        String remark = ReflectUtils.getValueByParaName(idsName, paraNames, paraValues);


        //  获取到了 对象中的集合
        List<Integer> idsList = ReflectUtils.parse2IntList(object);
        // todo 做一些保存操作的记录
    }
}

4:反射工具类

此处用了泛型,接收参数的值是通用的
package com.draymond.aop.spring.aspect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * 反射工具类
 *
 * @Auther: ZhangSuchao
 * @Date: 2020/7/29 20:18
 */
public class ReflectUtils {


    /**
     * 根据 idsName 从 paraValues获取对应索引处的值
     *
     * @param paraName
     * @param paraNames
     * @param paraValues
     * @param <T>
     * @return
     */
    public static <T> T getValueByParaName(String paraName, String[] paraNames, Object[] paraValues) {

        String[] paraNameSplit = paraName.split("-");
        int paraNameLength = paraNameSplit.length;
        if (paraNameSplit.length == 0) {
            return null;
        }

        // 获取第一个的值(orderDTO-ids中获取orderDTO的值)
        int index = ReflectUtils.getIndex(paraNameSplit[0], paraNames);

        if (index < 0) {
            return null;
        }
        Object object = ReflectUtils.getValue(index, paraValues);

        Object tempObj = object;

        try {


            for (int i = 0; i < paraNameLength - 1; i++) {

                Class<?> clz = object.getClass();
                Field paraField = clz.getDeclaredField(paraNameSplit[i + 1]);
                paraField.setAccessible(true);

                // Integet String...非集合类型
                if (Integer.class.isAssignableFrom(paraField.getType()) || String.class.isAssignableFrom(paraField.getType())) {
                    tempObj = paraField.get(object);
                }
                // 集合类型
                else if (List.class.isAssignableFrom(paraField.getType())) {
                    tempObj = ReflectUtils.getList(paraField, tempObj);

                }

            }

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return (T) tempObj;
    }

    /**
     * 反射获取list数据
     *
     * @param paraField 要获取值的属性名
     * @param tempObj   值源
     * @param <T>
     * @return
     */
    /**
     * 反射获取对象中的list数据
     *
     * @param object
     */
    public static <T> List<T> getList(Field field, Object object) {
        List<T> resultList = new ArrayList<>();
        if (object != null) {
            try {
                Class clzz = field.get(object).getClass();
                //反射调用获取到list的size方法来获取到集合的大小
                Method sizeMethod = clzz.getDeclaredMethod("size");
                if (!sizeMethod.isAccessible()) {
                    sizeMethod.setAccessible(true);
                }
                //集合长度
                int size = (int) sizeMethod.invoke(field.get(object));
                //循环遍历获取到数据
                for (int i = 0; i < size; i++) {
                    //反射获取到list的get方法
                    Method getMethod = clzz.getDeclaredMethod("get", int.class);
                    //调用get方法获取数据
                    if (!getMethod.isAccessible()) {
                        getMethod.setAccessible(true);
                    }

                    Object invoke = getMethod.invoke(field.get(object), i);
                    T var1 = (T) invoke;
                    resultList.add(var1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultList;
    }

    /**
     * 获取索引处的值
     *
     * @param index
     * @param paraValues
     * @return
     */
    private static Object getValue(int index, Object[] paraValues) {
        return (index >= 0 && paraValues.length > index) ? paraValues[index] : null;
    }

    /**
     * 获取 paraName 在 paraNames 中的索引位置
     *
     * @param paraName
     * @param paraNames
     * @return
     */
    private static int getIndex(String paraName, String[] paraNames) {

        for (int i = 0; i < paraNames.length; i++) {
            if (paraName.equals(paraNames[i])) {
                return i;
            }
        }
        return -1;

    }

    /**
     * 将object转换成List<Integer>
     *
     * @param object
     * @return
     */
    public static List<Integer> parse2IntList(Object object) {
        List<Integer> list = new ArrayList<>();

        if (object instanceof Integer) {
            list.add((Integer) object);
        } else if (object instanceof List) {
            // 此处要确保 object 是List<Integer> 否则类型转换异常
            list = (List) object;
        }
        return list;
    }
}

#备注:

优点
  1. 利用反射可以获取任何对象中的属性值,不论属性的位置多深(通过遍历获取的值:orderDTO-ids,获取ids的值)
  2. 使用泛型,获取值的结果类型可根据实际情况变化
    ######缺点:
    list之呢个在最后获取,如果list在中间层则需要进一步处理
3.重点方法(都使用泛型)

获取参数对应的值
public static <T> T getValueByParaName(String paraName, String[] paraNames, Object[] paraValues)
获取list
public static <T> List<T> getList(Field field, Object object)

本文地址:https://blog.csdn.net/Draymond_feng/article/details/107692148