最近在项目版本迭代中又一个这样的需求:
在已有的代码基础上添加接口调用日志,记录的日志内容主要针对的是修改记录的接口:
1、表数据的修改人,
2、修改的时间,
3、修改的记录的主键id,
4、接口的入参和出参。
通过注解我们很容易就能拿到接口的入参,出参,接口调用时间,接口的修改人,
但是唯独一个修改的记录对应的主键id这个东西不好处理,虽然接口入参中会有对应的id参数,但是却不好提取。。。考虑了一番后,在保证不做大量的改动前提上,
想出了一个解决方法-------》在接口的入参上加上日志信息类参数。
无中生有的操作就开始了,最终切面完成后的效果就是直接在方法上添加@Log,并且在入参上添加LogInfo,这个参数会直接在切面中实例化,方法上只需要直接往logInfo塞数据就行了
// 注解类
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
int targetId() default 0;
String apiName() default "";
int option() default 0;
}
import club.reedlu.www.boot.common.annotation.Log;
import club.reedlu.www.boot.common.vo.LogInfo;
import com.alibaba.fastjson.JSONObject;
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 java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@Aspect
@Component
public class LogImpl {
@Pointcut("@annotation(club.reedlu.www.boot.common.annotation.Log)")
public void pointCut(){}
@Around("pointCut()")
public Object arround(ProceedingJoinPoint joinPoint) {
// 内部实例化logInfo
LogInfo logInfo = new LogInfo();
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] args = joinPoint.getArgs();
Map<String,Object> map = new HashMap<>();
for(int i=0;i<parameterTypes.length;i++){
if(parameterTypes[i] == LogInfo.class){
if(args[i] == null){
// 如果取到的参数为null就用切面中的参数
args[i] = logInfo;
}else{
// 如果取到的值不为null就用接口的入参
logInfo = (LogInfo) args[i];
}
}else{
map.put(parameterTypes[i].getName(),args[i]);
}
}
Log logAnnotation = method.getAnnotation(Log.class);
logInfo.setApiName(logAnnotation.apiName());
logInfo.setTargetId(logAnnotation.targetId());
// 将入参转化为json字符串
logInfo.setParam(JSONObject.toJSONString(map));
Object result = null;
// 记录开始时间
long start = System.currentTimeMillis();
try {
result = joinPoint.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
// 记录接口调用时间
logInfo.setTime(end-start);
// 如果返回值在方法中已经设置类,就不再手动设置
if(StringUtils.isEmpty(logInfo.getResult())){
logInfo.setResult(JSONObject.toJSONString(result));
}
// 异步执行记录日志sql
System.out.println(logInfo);
return result;
}
}
在使用上的变化就是
从最开始的接口
@Override
public String sayHello() {
return "hello";
}
下面是记录日志的接口:
@Override
@Log(apiName = "sayHello")
public String sayHello(LogInfo logInfo) {
logInfo.setOption(1001);
// 记录修改对象对应的主键id
logInfo.setTargetId(1);
return "hello";
}
这种做法虽然解决了问题,但是这种无中生有的操作对于后期维护并不友好,我也不知道这种做法算不算是优化了。
本文介绍了一种在现有代码基础上优化接口调用日志的方法,通过在接口入参中加入日志信息类参数,实现了记录修改人、时间、主键ID及入参和出参的功能,探讨了此方法对后期维护的影响。
3518

被折叠的 条评论
为什么被折叠?



