一、pom.xml依赖配置

<!--spring切面aop依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

二、application.yml 添加配置

spring.aop.auto=true

三、创建一个自定义注解类,使用spring 的 aop 技术切到自定义注解上

package com.prison.extranet.config;

import com.prison.core.entity.SysUser;

import java.lang.annotation.*;

/**
 * @author WangJing
 * @Description 系统用户日志操作
 * @date 2021/6/24 22:24
 */
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface SysLogInterceptor {

    int source() default 1;

    String requestEvent() default "";

    String requestUrl() default "";

}

四、aop切面实现类

package com.prison.extranet.config;

import cn.hutool.json.JSONUtil;
import com.prison.common.enums.log.LogLevel;
import com.prison.common.util.IPUtils;
import com.prison.common.util.IdUtils;
import com.prison.core.entity.SysLog;
import com.prison.core.service.ISysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
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 java.lang.reflect.Method;

/**
 * @author WangJing
 * @Description 切面处理类
 * @date 2021/6/24 22:28
 */
@Slf4j
@Aspect
@Component
public class SysLogAspect {

    @Autowired
    ISysLogService sysLogService;

    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut("@annotation(com.prison.extranet.config.SysLogInterceptor)")
    public void logPoinCut() {

    }

    //切面 配置通知
    @AfterReturning(value = "logPoinCut()", returning = "resultData")
    public void saveSysLog(JoinPoint joinPoint, Object resultData) {
        log.info("处理日志信息");
        saveSysLogInfo(joinPoint, resultData, LogLevel.info);
    }

    @AfterThrowing(value = "logPoinCut()", throwing = "resultData")
    public void saveSysLogError(JoinPoint joinPoint, Throwable resultData) {
        log.info("处理异常日志");
        saveSysLogInfo(joinPoint, resultData, LogLevel.error);
    }

    private void saveSysLogInfo(JoinPoint joinPoint, Object resultData, LogLevel logLevel){
        //保存日志
        SysLog sysLog = new SysLog();
        sysLog.setLogNo(IdUtils.getUUID());
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();

        sysLog.setLogLevel(logLevel.getCode());

        //获取操作
        SysLogInterceptor myLog = method.getAnnotation(SysLogInterceptor.class);
        if (myLog != null) {
            sysLog.setSource(myLog.source());
            sysLog.setRequestUrl(myLog.requestUrl());
            sysLog.setRequestEvent(myLog.requestEvent());
        }
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        sysLog.setClassName(className);
        //获取请求的方法名
        String methodName = method.getName();
        sysLog.setMethodName(methodName);
        //请求的参数--将参数所在的数组转换成json
        Object[] args = joinPoint.getArgs();
        sysLog.setParams(JSONUtil.toJsonStr(args));
        String resultDataJsonStr = JSONUtil.toJsonStr(resultData);
        log.info("错误打印:{}", resultDataJsonStr);
        sysLog.setReturnData(resultDataJsonStr.substring(0, 200));//错误堆栈信息太长,只储存一部分
        if(!(LogLevel.error.getCode().equals(logLevel.getCode())
                && "login".equals(methodName))){//登录失败无法获取用户信息
            sysLog.setCreateBy(SysUserContextHolder.getUser().getUserNo());
        }
        //获取用户ip地址
        ServletRequestAttributes requestAttributes = ServletRequestAttributes.class.
                cast(RequestContextHolder.getRequestAttributes());
        sysLog.setVisitIp(IPUtils.getIpAddr(requestAttributes.getRequest()));
        //调用service保存SysLog实体类到数据库
        sysLogService.insertSysLog(sysLog);
        SysUserContextHolder.clear();
    }

}

五、方法中添加自定义注解

@SysLogInterceptor(source = 1, requestEvent = "登录", requestUrl = "/login")

六、注释总结

@Aspect:注解将一个java类定义为切面类

@Pointcut:定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。

根据需要在切入点不同位置的切入内容:

@Before:在切入点开始处切入内容

@After:在切入点结尾处切入内容

@AfterReturning:在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)

@Around:在切入点前后切入内容,并自己控制何时执行切入点自身的内容

@AfterThrowing:用来处理当切入内容部分抛出异常之后的处理逻辑

注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!