AOP实现日志记录
自定义注解方式 实现
1、总体图
2、注解类SystemLog
SystemLog
package com.sangeng.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) //@SystemLog注解 保持到 runtime阶段
@Target({ElementType.METHOD}) //指定@SystemLog注解 加在method上,表示某个method受aop切面增强
public @interface SystemLog {
//使用aop,1.写 自定义注解 @SystemLog
String businessName(); //属性,指定业务名称 “更新用户信息”
}
3、切面类LogAspect
handleBefore 在请求执行之前 执行这个方法
handleAfter 在请求执行之后 执行这个方法
LogAspect文章来源:https://www.toymoban.com/news/detail-624385.html
package com.sangeng.aspect;
import com.alibaba.fastjson.JSON;
import com.sangeng.annotation.SystemLog;
import lombok.extern.slf4j.Slf4j;
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.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Component //切面类要注入spring容器
@Aspect //告诉spring这是 一个切面类
@Slf4j // log日志
public class LogAspect {
//使用aop,2. 定义切面类LogAspect
//切面 = 切点 + 通知
// 2.1确定切点(重点:在方法上加注解,指定切点) 注解方式(写自定义注解@SystemLog的全类名)
@Pointcut("@annotation(com.sangeng.annotation.SystemLog)") //自定义注解SystemLog的 全类名
public void pt(){
// 被增强方法,目标方法:controller中 @PutMapping("/userInfo")对应的方法
//joinPoint:被增强方法(目标方法)的信息 封装成一个对象
}
// 2.2通知方法 (增强的代码)
@Around("pt()") //环绕通知:指定使用的切点---指定pt()方法上所使用的切点
public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable { //joinPoint:被增强方法(目标方法)的信息 封装成一个对象
// 环绕通知是前置,执行,异常,最终四个通知
Object ret; //Around必须调用proceed()让目标方法执行,不然目标方法不会执行
try {
handleBefore(joinPoint);//目标方法之前 执行
ret = joinPoint.proceed(); //这个异常,这里不能用try-catch,否则controller层的异常都在这被捕获了,so,要往上抛出异常
handleAfter(ret); //目标方法之后 执行 参数ret是目标方法执行后返回ResponseResult类型
} finally { //最终 都要执行的代码:打印日志信息
// 结束后换行
log.info("=======End=======" + System.lineSeparator()); //System.lineSeparator()获取当前系统换行符
}
return ret; //目标方法执行后,要有返回值,不然目标方法没有返回值
}
private void handleBefore(ProceedingJoinPoint joinPoint) {
// 看到类名后面有Holder 一般表示这个类 使用ThreadLocal进行数据共享,保证多个线程之间资源的隔离
// RequestAttributes -> ServletRequestAttributes(实现类) 可以获取request
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest(); //得到request
//获取被增强方法上的注解对象 被增强方法:controller中 @PutMapping("/userInfo")对应的方法
SystemLog systemLog = getSystemLog(joinPoint); // 需要joinPoint对象
log.info("=======Start=======");
// 打印请求 URL
log.info("URL : {}",request.getRequestURL()); //获取当前线程请求对象, url是在request对象当中(URL在http报文的request部分)
// 打印描述信息 业务名字,接口名字
log.info("BusinessName : {}", systemLog.businessName());
// 打印 Http method
log.info("HTTP Method : {}", request.getMethod());
// 打印调用 controller 的全路径以及执行方法 类名 方法名
log.info("Class Method : {}.{}",joinPoint.getSignature().getDeclaringType(),
((MethodSignature) joinPoint.getSignature()).getName());
// 打印请求的 IP
log.info("IP : {}",request.getRemoteHost());
// 打印请求入参
log.info("Request Args : {}", JSON.toJSONString(joinPoint.getArgs())); //数组转成json字符串
}
private void handleAfter(Object ret) {
// 打印出参
log.info("Response : {}",JSON.toJSONString(ret) );
}
private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {
// 被增强方法,目标方法:controller中 @PutMapping("/userInfo")对应的方法
//joinPoint:被增强方法(目标方法)的信息 封装成一个对象,叫做签名Signature
MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取目标方法
SystemLog systemLog = signature.getMethod().getAnnotation(SystemLog.class);
return systemLog;
}
}
4、测试
运行项目,访问 @PutMapping(“/user/userInfo”) 即可打印日志信息。
这个请求之前的日志 -> handleAfter
这个请求之后的日志 -> handleBefore文章来源地址https://www.toymoban.com/news/detail-624385.html
到了这里,关于AOP实现日志记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!