使用Spring AOP做一个日志切面类
日志切面类用于记录Controller层的方法执行前和执行后的日志信息。定义一个切面类,并在该类中声明增强方法(如@Before、@After、@Around等注解的方法),然后在这些增强方法中通过JoinPoint参数获取当前连接点的信息,如方法名、参数、目标对象等。最后,在配置文件中声明切面和切点,将增强方法与切点关联起来,实现切面逻辑的插入。
1 package com.venux.train.common.aspect; 2 3 import cn.hutool.core.util.RandomUtil; 4 import com.alibaba.fastjson.JSONObject; 5 import com.alibaba.fastjson.support.spring.PropertyPreFilters; 6 import jakarta.servlet.ServletRequest; 7 import jakarta.servlet.ServletResponse; 8 import jakarta.servlet.http.HttpServletRequest; 9 import org.aspectj.lang.JoinPoint; 10 import org.aspectj.lang.ProceedingJoinPoint; 11 import org.aspectj.lang.Signature; 12 import org.aspectj.lang.annotation.Around; 13 import org.aspectj.lang.annotation.Aspect; 14 import org.aspectj.lang.annotation.Before; 15 import org.aspectj.lang.annotation.Pointcut; 16 import org.slf4j.Logger; 17 import org.slf4j.LoggerFactory; 18 import org.slf4j.MDC; 19 import org.springframework.stereotype.Component; 20 import org.springframework.web.context.request.RequestContextHolder; 21 import org.springframework.web.context.request.ServletRequestAttributes; 22 import org.springframework.web.multipart.MultipartFile; 23 24 @Aspect 25 @Component 26 public class LogAspect { 27 public LogAspect() { 28 System.out.println("Common LogAspect"); 29 } 30 31 private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class); 32 33 /** 34 * 定义一个切点 35 */ 36 @Pointcut("execution(public * com.venux..*Controller.*(..))") 37 public void controllerPointcut() { 38 } 39 40 @Before("controllerPointcut()") 41 public void doBefore(JoinPoint joinPoint) { 42 43 44 // 开始打印请求日志 45 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 46 HttpServletRequest request = attributes.getRequest(); 47 Signature signature = joinPoint.getSignature(); 48 String name = signature.getName(); 49 50 // 打印请求信息 51 LOG.info("------------- 开始 -------------"); 52 LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod()); 53 LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name); 54 LOG.info("远程地址: {}", request.getRemoteAddr()); 55 56 // 打印请求参数 57 Object[] args = joinPoint.getArgs(); 58 // LOG.info("请求参数: {}", JSONObject.toJSONString(args)); 59 60 // 排除特殊类型的参数,如文件类型 61 Object[] arguments = new Object[args.length]; 62 for (int i = 0; i < args.length; i++) { 63 if (args[i] instanceof ServletRequest 64 || args[i] instanceof ServletResponse 65 || args[i] instanceof MultipartFile) { 66 continue; 67 } 68 arguments[i] = args[i]; 69 } 70 // 排除字段,敏感字段或太长的字段不显示:身份证、手机号、邮箱、密码等 71 String[] excludeProperties = {}; 72 PropertyPreFilters filters = new PropertyPreFilters(); 73 PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter(); 74 excludefilter.addExcludes(excludeProperties); 75 LOG.info("请求参数: {}", JSONObject.toJSONString(arguments, excludefilter)); 76 } 77 78 @Around("controllerPointcut()") 79 public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { 80 long startTime = System.currentTimeMillis(); 81 Object result = proceedingJoinPoint.proceed(); 82 // 排除字段,敏感字段或太长的字段不显示:身份证、手机号、邮箱、密码等 83 String[] excludeProperties = {}; 84 PropertyPreFilters filters = new PropertyPreFilters(); 85 PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter(); 86 excludefilter.addExcludes(excludeProperties); 87 LOG.info("返回结果: {}", JSONObject.toJSONString(result, excludefilter)); 88 LOG.info("------------- 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime); 89 return result; 90 } 91 92 }