一、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:用来处理当切入内容部分抛出异常之后的处理逻辑
注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!