什么是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,很不方便。所以想把日志都记录到数据库,方便排查问题。
实现过程
- 引入aop依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 自定义注解类
import java.lang.annotation.*;
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented
public @interface SystemLogAnnotation {
String value() default "";
}
- 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);
}
}
- 数据库日志实体类
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