AOP实现操作日志记录

文章目录

    • 1.common-log4j2-starter
        • 1.目录
        • [2.pom.xml 引入依赖](#2.pom.xml 引入依赖)
        • 3.LogAspect.java
        • [4.Log4j2AutoConfiguration.java Log4j2自动配置类条件注入切面类](#4.Log4j2AutoConfiguration.java Log4j2自动配置类条件注入切面类)
    • [2.common-log4j2-starter-demo 测试](#2.common-log4j2-starter-demo 测试)

1.common-log4j2-starter

1.目录
2.pom.xml 引入依赖
xml 复制代码
<!-- aop -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- gson -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>
3.LogAspect.java
java 复制代码
package com.sunxiansheng.log4j2.aspectj;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;

@Aspect
@Slf4j
public class LogAspect {

    // 使用 Gson 序列化对象,启用 PrettyPrinting,输出格式化的 JSON
    private static final Gson GSON = new GsonBuilder()
            .setPrettyPrinting() // 启用格式化输出
            .disableHtmlEscaping() // 禁用 HTML 转义,保留字符原始形式
            .create();

    // ANSI 颜色代码
    private static final String ANSI_RESET = "\u001B[0m";     // 重置颜色
    private static final String ANSI_CYAN = "\u001B[92m";     // 绿色

    /**
     * 配置切点,匹配 Controller 和 Service 层的所有方法
     */
    @Pointcut("execution(* com.sunxiansheng..controller..*(..)) || execution(* com.sunxiansheng..service..*(..))")
    public void applicationPackagePointcut() {
        // 方法为空,这是一个切点定义
    }

    /**
     * 环绕通知,记录方法执行的详细信息
     *
     * @param joinPoint 切入点
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Around("applicationPackagePointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名和详细信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String className = signature.getDeclaringTypeName();
        String methodName = signature.getName();

        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        String requestParams = GSON.toJson(args);

        // 记录方法进入日志,参数从下一行开始输出,参数部分以黄色显示
        log.info("==> 进入方法: {}.{}()", className, methodName);
        log.info("参数:\n" + ANSI_CYAN + "{}" + ANSI_RESET, requestParams);

        // 记录方法执行开始时间
        long startTime = System.currentTimeMillis();

        Object result;
        try {
            // 执行目标方法
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            // 捕获并记录异常信息,堆栈信息从下一行开始输出
            String exceptionStackTrace = getStackTraceAsString(throwable);
            log.error("<== 方法异常: {}.{}() | 异常信息: {}", className, methodName, throwable.getMessage());
            log.error("堆栈信息:\n{}", exceptionStackTrace);
            throw throwable;  // 重新抛出异常,保持原有异常机制
        }

        // 记录方法执行结束时间
        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime;

        // 获取方法返回值
        String response = GSON.toJson(result);

        // 记录方法退出日志,返回值从下一行开始输出,返回值部分以黄色显示
        log.info("<== 退出方法: {}.{}() | 耗时: {} ms", className, methodName, executionTime);
        log.info("返回值:\n" + ANSI_CYAN + "{}" + ANSI_RESET, response);

        return result;
    }

    /**
     * 将异常的堆栈信息转换为字符串
     *
     * @param throwable 异常
     * @return 堆栈信息字符串
     */
    private String getStackTraceAsString(Throwable throwable) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : throwable.getStackTrace()) {
            sb.append("\tat ").append(element.toString()).append("\n");
        }
        return sb.toString();
    }
}
4.Log4j2AutoConfiguration.java Log4j2自动配置类条件注入切面类
java 复制代码
package com.sunxiansheng.log4j2.config;

import com.sunxiansheng.log4j2.aspectj.LogAspect;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description: Log4j2自动配置类
 *
 * @Author sun
 * @Create 2024/10/24 10:36
 * @Version 1.0
 */
@Configuration
public class Log4j2AutoConfiguration {

    /**
     * 条件注入LogAspect
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "log.aspect.enable", havingValue = "true", matchIfMissing = true)
    LogAspect logAspect() {
        return new LogAspect();
    }
}

2.common-log4j2-starter-demo 测试

1.目录
2.application.yml 启用日志切面
yaml 复制代码
log:
  aspect:
    enable: true # 开启自定义的日志切面
3.TraceController.java
java 复制代码
/**
 * 测试的Bean,入参
 */
@Data
static class AspectBeanIn {
    private String name;
    private Integer age;
    private String phone;
}

/**
 * 测试的Bean,出参
 */
@Data
static class AspectBeanOut {
    private String name;
    private Integer age;
    private String phone;
}

@RequestMapping("/aspect")
public AspectBeanOut aspect(@RequestBody AspectBeanIn aspectBeanIn) {
    AspectBeanOut aspectBean = new AspectBeanOut();
    aspectBean.setName("sun");
    aspectBean.setAge(18);
    aspectBean.setPhone("123456789");
    // 出现异常
    int i = 1 / 0;
    return aspectBean;
}
4.结果
相关推荐
_未知_开摆8 分钟前
CSS | CSS实现两栏布局(左边定宽 右边自适应,左右成比自适应)
java·前端·javascript·css·html·css3
华子w90892585911 分钟前
基于Java+SpringMvc+Vue技术的宠物分享平台
java·开发语言·宠物
白宇横流学长17 分钟前
基于Java的推箱子游戏设计与实现
java·python·游戏
baozhengw17 分钟前
SpringBoot项目实战(41)--Beetl网页使用自定义函数获取新闻列表
java·前端·spring boot
程序员老石24 分钟前
Clickhouse基础(一)
java·开发语言·clickhouse
qq_413066101 小时前
tdengine数据库使用java连接
java·数据库·tdengine
快乐就好ya2 小时前
win下搭建elk并集成springboot
java·spring boot·后端·spring·elk·spring cloud
温柔了岁月.c3 小时前
SpringAop
java·spring aop·动态代理·切面编程
My LQS3 小时前
通过 Caffeine 和 Spring Cache 的集成,实现高性能的本地缓存
java·spring·缓存