使用注解AOP实现方法日志记录,免去重复写日志存储的麻烦。该方案能记录方法请求参数,返回结果等信息
代码结构:
1.自定义注解
package com.example.demo.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在方法上使用该注解时,Spring会自动存储被注解方法的请求参数和返回信息到log表
* 存储的基础字段包括:
* businessItemId:方法名称
* requestParameter:请求的参数名称以及参数值
* responseContent:请求的返回
* result:如果程序正常运行则存储success,否则存储failure
* types:传参中的logType(根据注解中的传参决定,非必填)
* typesName:types对应的名称
* businessId:传参中的businessId字段(根据注解中的传参决定,非必填)
* createTime:创建时间
* updateTime:更新时间
* note:如果程序异常执行,note字段存储e.getMessage()
* @author shengsheng
*/
// 方法注解
@Target(ElementType.METHOD)
// 运行时可见
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnno {
/**
* log的types字段
* @return
*/
String logType() default "";
/**
* log的businessId字段
* @return
*/
String businessId() default "";
}
2.切面实现
package com.example.demo.aop;
import com.alibaba.fastjson.JSON;
import com.example.demo.entity.Log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Log的AOP实现日志
* @author shengsheng
*
*/
@Component
@Aspect
public class LogAspect {
/*@Autowired
private LogMapper logMapper;*/
@Pointcut("@annotation(com.example.demo.aop.LogAnno)")
public void logPointCut() {
}
/**
* 环绕通知记录日志通过注解匹配到需要增加日志功能的方法
* @param pjp
* @return
* @throws Throwable
*/
@Around("logPointCut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
Log log = new Log();
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature)signature;
// 1.方法执行前的处理,相当于前置通知
// 获取正在访问的类
Class executionClass = pjp.getTarget().getClass();
// 获取访问的方法的名称
String methodName = pjp.getSignature().getName();
// 获取正在访问的方法
Method executionMethod =methodSignature.getMethod();
// 获取访问的方法的参数
Object[] args = pjp.getArgs();
//获取方法中的参数名称
ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
String[] parameterNames = pnd.getParameterNames(executionMethod);
log.setBusinessItemId(methodName);
if((parameterNames!=null)&&(parameterNames.length>0)&&(args!=null)&&(args.length>0)){
Map<String,Object> requestParams = new HashMap<>(args.length);
for (int i = 0 ;i<parameterNames.length;i++) {
requestParams.put(parameterNames[i],args[i]);
}
//设置请求参数
log.setRequestParameter(JSON.toJSONString(requestParams));
}
LogAnno annotation = executionMethod.getAnnotation(LogAnno.class);
//获取注解中的types字段
String logTypeStr = annotation.logType();
if(!StringUtils.isEmpty(logTypeStr)){
Integer logType = Integer.valueOf(logTypeStr);
log.setTypes(logType);
log.setTypesName("");
}
String businessId = annotation.businessId();
log.setBusinessId(businessId);
Object result = null;
try {
//让代理方法执行
result = pjp.proceed();
// 2.后置通知
log.setResult("success");
} catch (Exception e) {
// 3.异常通知
log.setResult("failure");
log.setNote(e.getMessage());
} finally {
// 4.最终通知
Date now = new Date();
log.setCreateTime(now);
log.setResponseContent(JSON.toJSONString(result));
log.setUpdateTime(now);
System.out.println(log);
//入库
// logMapper.insertSelective(log);
}
return result;
}
}
3.在方法上使用注解
package com.example.demo.utils;
import com.example.demo.aop.LogAnno;
import org.springframework.stereotype.Component;
/**
* description:
*
* @author shengsheng
* @date 2020/9/24 16:32
*/
@Component
public class CalculateUtils {
//使用注解
@LogAnno(logType = "1",businessId = "div")
public Integer div(Integer a,Integer b){
return a/b;
}
}
4.测试
package com.example.demo.test;
import com.example.demo.utils.CalculateUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* description:
*
* @author shengsheng
* @date 2020/9/24 16:48
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculateTest {
@Autowired
private CalculateUtils calculateUtils;
@Test
public void test() {
Integer div = calculateUtils.div(1, 1);
System.out.println(div);
}
}
5.测试结果
Log{id=null, types=1, typesName='', businessId='div', businessItemId='div', result='success', requestParameter='{"a":1,"b":1}', responseContent='1', note='null', createTime=Thu Sep 24 17:12:57 CST 2020, updateTime=Thu Sep 24 17:12:57 CST 2020}
版权声明:本文为shengshenglalalala原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。