SpringBoot 实现 AOP记录请求和响应的内容保存到数据库

什么是AOP

AOP(Aspect Oriented Programming)就是面向切面编程,是OOP(Object Oriented Programming)面向对象编程的补充和完善。
OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。
参考:
https://www.jianshu.com/p/94879042db88
https://www.bilibili.com/video/BV1yK411M7hb?from=search&seid=6881767931548601261&spm_id_from=333.337.0.0

实现目的

我用的是docker环境部署,每次查看日志都要到docker容器里面去看log,很不方便。所以想把日志都记录到数据库,方便排查问题。

实现过程

  1. 引入aop依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 自定义注解类
import java.lang.annotation.*;

@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented
public @interface SystemLogAnnotation {
    String value() default "";
}
  1. aop切面实现类
package com.example.shuadanxitongapi.aspect;

import cn.hutool.core.net.NetUtil;
import com.alibaba.fastjson.JSONObject;
import com.example.shuadanxitongapi.annotation.SystemLogAnnotation;
import com.example.shuadanxitongapi.entity.SystemLog;
import com.example.shuadanxitongapi.mapper.SystemLogMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 日志记录
 *
 * @author ouyangyz
 * @create 2022-03-07 10:50
 */
@Aspect
@Component
public class SystemLogAspect {
    @Autowired
    SystemLogMapper systemlogMapper;

    @Pointcut("@annotation(com.example.shuadanxitongapi.annotation.SystemLogAnnotation)")
    public void logPointCut() {

    }

    //统计请求的处理时间
    Long startTime = null;

    @Before("logPointCut()")
    public void beforeRequest() {
        startTime = System.currentTimeMillis();
    }

    @AfterReturning(value = "logPointCut()", returning = "result")
    public void saveLog(JoinPoint joinPoint, Object result) {
        System.out.println("切面。。。。。");
        //保存日志
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        HttpServletResponse response = requestAttributes.getResponse();

        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        //获取切入点所在的方法
        Method method = signature.getMethod();

        SystemLog systemLog = new SystemLog();
        //获取操作
        SystemLogAnnotation systemLogAnnotation = method.getAnnotation(SystemLogAnnotation.class);
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        if (systemLogAnnotation != null) {
            String value = systemLogAnnotation.value();
            systemLog.setSName(value);
        }
        systemLog.setDNewDate(LocalDateTime.now());
        systemLog.setIp(NetUtil.getLocalhostStr());
        systemLog.setMethod(request.getMethod());
        systemLog.setJsonRequest(JSONObject.toJSONString(request.getParameterMap()));
        systemLog.setRequestUrl(request.getRequestURL().toString());
        systemLog.setRequestPath(className + "." + methodName);
        systemLog.setHttpStatus(response.getStatus());
        systemLog.setJsonResponse(JSONObject.toJSONString(result));
        systemLog.setUserTime((System.currentTimeMillis() - startTime));
        System.out.println(systemLog);
        systemlogMapper.insert(systemLog);
    }
}

  1. 数据库日志实体类
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.time.LocalDateTime;

/**
 * <p>
 *
 * </p>
 *
 * @author ouyangyz
 * @since 2022-03-07
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("systemlog")
public class SystemLog extends CommonEntity {

    private static final long serialVersionUID = 1L;

    @TableId(value = "lID", type = IdType.AUTO)
    private Integer lID;

    /**
     * 名称
     */
    @TableField("sName")
    private String sName;

    /**
     * IP地址
     */
    private String ip;
    /**
     * IP地址
     */
    @TableField("dNewDate")
    private LocalDateTime dNewDate;

    /**
     * 请求类型:get/post
     */
    private String method;

    /**
     * 模块名称
     */
    private String category;

    /**
     * 请求地址
     */
    @TableField("requestUrl")
    private String requestUrl;

    /**
     * 请求路径
     */
    @TableField("requestPath")
    private String requestPath;

    /**
     * 请求参数
     */
    @TableField("jsonRequest")
    private String jsonRequest;

    /**
     * 响应状态码
     */
    @TableField("httpStatus")
    private int httpStatus;

    /**
     * 响应内容
     */
    @TableField("jsonResponse")
    private String jsonResponse;

    /**
     * 响应时间
     */
    @TableField("userTime")
    private long userTime;
}

数据库记录效果
在这里插入图片描述

参考:
https://www.cnblogs.com/shihaiming/p/9565892.html?ivk_sa=1024320u

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值