aop+反射:日志切面(获取list及其他类型值)
程序员文章站
2022-04-01 10:51:05
#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;
}
}
#备注:
优点
- 利用反射可以获取任何对象中的属性值,不论属性的位置多深(通过遍历获取的值:orderDTO-ids,获取ids的值)
- 使用泛型,获取值的结果类型可根据实际情况变化
######缺点:
list之呢个在最后获取,如果list在中间层则需要进一步处理
3.重点方法(都使用泛型)
获取参数对应的值public static <T> T getValueByParaName(String paraName, String[] paraNames, Object[] paraValues)
获取listpublic static <T> List<T> getList(Field field, Object object)
本文地址:https://blog.csdn.net/Draymond_feng/article/details/107692148