自定义注解实现日志记录

自定义注解实现日志记录

引入所需的依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>版本号</version>
    <relativePath/>
</parent>
<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-aop</artifactId>
     </dependency>
     <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
     <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.42</version>
        </dependency>
</dependencies>

自定义注解(LogAnnotation)

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
    //模块标题
    String title() default "";

    //日志内容
    String content() default "";
}

定义日志类

@Data
public class Log {
    private String title;//模块标题
    private String content; //日志内容
    private String method; //方法名称
    private String requestMethod; //请求方式
    private String name; // 操作人员名称
    private String requestUrl; //请求URL
    private String requestIp; //请求IP
    private String ipLocation;//ip归属
    private String requestParam; //请求参数
    private String responseParam; //响应参数
    private Integer status; //操作状态 (0正常,1异常)
    private String error; //错误信息
    private Date executeTime; //执行时间
    private Long takeTime; //该方法耗时(毫秒)
}

定义AOP切面类

用于拦截带有 @LogAnnotation 注解的方法,并记录日志

package com.chs.aspect;

import com.alibaba.fastjson.JSON;
import com.chs.annocation.LogAnnotation;
import com.chs.domain.Log;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.mvc.condition.RequestConditionHolder;

import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
public class LogAspect {
    @Pointcut("@annotation(com.chs.annocation.LogAnnotation)")
    public void logPointcut() {
    }

    //用于记录方法的执行时间
    ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Before("logPointcut()")
    public void beforeMethod() {
        startTime.set(System.currentTimeMillis());
    }

    /**
     * 设置操作异常切入点记录异常日志 扫描所有controller包下操作
     */
    @Pointcut("execution(* com.chs.controller..*(..))")
    public void allControllerPointCut() {
    }

    @AfterReturning("allControllerPointCut()")
    public void saveLog(JoinPoint joinPoint) {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        assert requestAttributes != null;
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        try {
            //创建日志对象
            Log log = new Log();
            //从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            // 获取切入点所在的方法
            Method m = methodSignature.getMethod();
            // 获取方法上的注解对象
            LogAnnotation annotation = m.getAnnotation(LogAnnotation.class);
            // 获取值
            String title = annotation.title();
            log.setTitle(title);
            String content = annotation.content();
            log.setContent(content);
            // 将入参转换成json
//            String params = argsArrayToString(joinPoint.getArgs());
            //设置请求参数
//            log.setRequestParam(params);
            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            // 获取请求的方法名
            String methodName = m.getName();
            methodName = className + "." + methodName + "()";
            log.setMethod(methodName);
            //获取请求的方法
            String method = request.getMethod();
            log.setName(method);
            //获取请求方式
            String requestMethod = request.getMethod();
            log.setRequestMethod(requestMethod);
            //获取操作人员名称
            log.setName("张三");
            //获取请求IP的归属地址
            log.setIpLocation("陕西");
            //获取请求URI
            String requestURI = request.getRequestURI();
            log.setRequestUrl(requestURI);
            //获取IP地址
            String Ip = this.getIp(request);
            log.setRequestIp(Ip);
            //获取返回结果
//            String res = JSON.toJSONString(result);
//            log.setResponseParam(res);
            //设置操作状态
            log.setStatus(0);
            //设置执行时间
            log.setExecuteTime(new Date());
            //设置耗时时间
            Long takeTime = System.currentTimeMillis() - startTime.get();
            log.setTakeTime(takeTime);

            System.out.println("log = " + log);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    @AfterThrowing(pointcut = "allControllerPointCut()", throwing = "e")
    public void saveErrorLog(JoinPoint joinPoint, Throwable e) {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        assert requestAttributes != null;
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        try {
            //创建日志对象
            Log log = new Log();
            //从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            // 获取切入点所在的方法
            Method m = methodSignature.getMethod();
            // 获取方法上的注解对象
            LogAnnotation annotation = m.getAnnotation(LogAnnotation.class);
            // 获取值
            String title = annotation.title();
            log.setTitle(title);
            String content = annotation.content();
            log.setContent(content);
            // 将入参转换成json
//            String params = argsArrayToString(joinPoint.getArgs())
            //设置请求参数
//            log.setRequestParam(params);
            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            // 获取请求的方法名
            String methodName = m.getName();
            methodName = className + "." + methodName + "()";
            log.setMethod(methodName);
            //获取请求的方法
            String method = request.getMethod();
            log.setName(method);
            //获取请求方式
            String requestMethod = request.getMethod();
            log.setRequestMethod(requestMethod);
            //获取操作人员名称
            log.setName("张三");
            //获取请求IP的归属地址
            log.setIpLocation("陕西");
            //获取请求URI
            String requestURI = request.getRequestURI();
            log.setRequestUrl(requestURI);
            //获取IP地址
            String Ip = this.getIp(request);
            log.setRequestIp(Ip);
            //获取返回结果
//            String res = JSON.toJSONString(result);
//            log.setResponseParam(res);
            //设置操作状态
            log.setStatus(0);
            //设置执行时间
            log.setExecuteTime(new Date());
            //设置耗时时间
            Long takeTime = System.currentTimeMillis() - startTime.get();
            log.setTakeTime(takeTime);
            //设置错误信息
            log.setError(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));

            System.out.println("log = " + log);
        } catch (Throwable e2) {
            e2.printStackTrace();
        }
    }

    //转换异常信息为字符串
    private String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            strbuff.append(stet + "\n");
        }
        String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
        message = substring(message, 0, 2000);
        return message;
    }

    //字符串截取
    public static String substring(String str, int start, int end) {
        if (str == null) {
            return null;
        } else {
            if (end < 0) {
                end += str.length();
            }

            if (start < 0) {
                start += str.length();
            }

            if (end > str.length()) {
                end = str.length();
            }

            if (start > end) {
                return "";
            } else {
                if (start < 0) {
                    start = 0;
                }

                if (end < 0) {
                    end = 0;
                }
                return str.substring(start, end);
            }
        }
    }

    //根据HttpServletRequest获取访问者的IP地址
    private String getIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

使用自定义注解的控制器

@LogAnnotation(title = "用户模块", content = "删除用户操作")
@GetMapping("/delete/{userId}")
public String delete(@PathVariable("userId") Long userId){
  System.out.println("userId = " + userId);
  int i=10/0; //测试异常日志
  return "成功";
}

注意:记得在主启动类上加:@EnableAspectJAutoProxy

posted @   CH_song  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示