在上篇文章中,我们使用了AOP思想实现日志记录的功能,代码中采用了指定连接点方式(@Pointcut(“execution(* com.nowcoder.community.controller..(…))”)),指定后不需要在进行任何操作就可以记录日志了,但是如果我们对某些controller不想记录日志,就需要更改指定的切点,灵活性较差。因此采用注解+AOP方式,实现更灵活的日志记录功能。
package com.nowcoder.community.annotation;
import java.lang.annotation.*;
/**
* @author Janson
* @Description AOP日志记录注解
* @Date 2023/5/12
* @Target LogAspect 注解的作用目标
* @Retention 指定注解的保留时间
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAspect {
/**
* title 自定义名称
* description 自定义描述
* @return
*/
String title() default "";
String description() default "";
}
定义切点(织入点)
execution(* com.nowcoder.community.controller..(…))
- 第一个 * 表示 支持任意类型返回值的方法
- com.nowcoder.community.controller 表示这个包下的类
- 第二个 * 表示 controller包下的任意类
- 第三个 * 表示 类中的任意方法
- (…) 表示方法可以拥有任意参数
可以根据自己的需求替换。
package com.nowcoder.community.aspect;
import com.nowcoder.community.annotation.LogAspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* @author Janson
* @Description AOP日志记录,此方案不统一设置连接点 @Pointcut,而是采用注解方式,指定连接的方法
* @Date 2023/5/12
*/
@Aspect
@Component
public class LogAspectAnnotationTest {
/**
* 定义切点(织入点)
* execution(* com.nowcoder.community.controller.*.*(..))
* - 第一个 * 表示 支持任意类型返回值的方法
* - com.nowcoder.community.controller 表示这个包下的类
* - 第二个 * 表示 controller包下的任意类
* - 第三个 * 表示 类中的任意方法
* - (..) 表示方法可以拥有任意参数
* 可以根据自己的需求替换。
*
*/
@Before(value = "@annotation(controllerLog)")
public void before(JoinPoint joinPoint, LogAspect controllerLog){
String className = joinPoint.getClass().getName();
String methodName = joinPoint.getSignature().getName();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
String ip = attributes.getRequest().getRemoteHost();
String requestURI = attributes.getRequest().getRequestURI();
String requestMethod = attributes.getRequest().getMethod();
String title = controllerLog.title();
String description = controllerLog.description();
System.out.println("title is " + title + ",description is " + description);
System.out.println("before excute ······");
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
}
@After(value = "@annotation(controllerLog)")
public void after(JoinPoint joinPoint, LogAspect controllerLog){
String className = joinPoint.getClass().getName();
String methodName = joinPoint.getSignature().getName();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
String ip = attributes.getRequest().getRemoteHost();
String requestURI = attributes.getRequest().getRequestURI();
String requestMethod = attributes.getRequest().getMethod();
String title = controllerLog.title();
String description = controllerLog.description();
System.out.println("title is " + title + ",description is " + description);
System.out.println("after excute ······");
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
}
@AfterReturning(value = "@annotation(controllerLog)")
public void afterReturning(JoinPoint joinPoint, LogAspect controllerLog){
String className = joinPoint.getClass().getName();
String methodName = joinPoint.getSignature().getName();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
String ip = attributes.getRequest().getRemoteHost();
String requestURI = attributes.getRequest().getRequestURI();
String requestMethod = attributes.getRequest().getMethod();
String title = controllerLog.title();
String description = controllerLog.description();
System.out.println("title is " + title + ",description is " + description);
System.out.println("afterReturning excute ······");
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
}
@AfterThrowing(value = "@annotation(controllerLog)",throwing = "e")
public void afterThrowing(JoinPoint joinPoint, LogAspect controllerLog,Exception e){
String className = joinPoint.getClass().getName();
String methodName = joinPoint.getSignature().getName();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
String ip = attributes.getRequest().getRemoteHost();
String requestURI = attributes.getRequest().getRequestURI();
String requestMethod = attributes.getRequest().getMethod();
String title = controllerLog.title();
String description = controllerLog.description();
System.out.println("title is " + title + ",description is " + description);
System.out.println("afterThrowing excute ······" + e.getMessage());
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s],请求失败原因: [%s]", ip,
requestURI, requestMethod,className,methodName,e.getMessage()));
}
@Around(value = "@annotation(controllerLog)")
public void around(ProceedingJoinPoint joinPoint, LogAspect controllerLog) throws Throwable {
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
System.out.println("className is : " + className + ". methodName is : " + methodName);
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
// 请求ip
String ip = attributes.getRequest().getRemoteHost();
// 请求路径
String requestURI = attributes.getRequest().getRequestURI();
// 请求方法
String requestMethod = attributes.getRequest().getMethod();
String title = controllerLog.title();
String description = controllerLog.description();
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
Object obj = null;
try {
obj = joinPoint.proceed();
} catch (Throwable e) {
System.out.println("我捕获了异常");
throw new RuntimeException("执行失败",e);
}
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
System.out.println("around excute after ········");
}
}