Spring Boot AOP 切面编程
概述

- 所有函数都要加代码, 繁琐;
demo

概念

执行流程

- 使用代理对象 进行注入;
进阶

切点引用 pointCut

- pt 函数改为 public , 其他aspect 类中也可以引用
通知顺序



切入点表达式
execution

- 只写方法名, 会匹配所有同名方法; ;因此不建议省略包名类名;


annotation



连接点

案例 记录日志
获取token
- 获取token直接从请求header中获取,不要从后端其他类中获取
package org.hzl.aop;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.hzl.mapper.OperateLogMapper;
import org.hzl.pojo.OperateLog;
import org.hzl.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Arrays;
@Slf4j
@Component
@Aspect
public class LogAspect {
@Autowired
private OperateLogMapper operateLogMapper;
@Autowired
private HttpServletRequest request;
@Around("@annotation(org.hzl.anno.Log)")
public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取emp 姓名 , 从 request 中jwt 令牌中获取
String token = request.getHeader("token");
Claims claims = JwtUtils.parseToken(token);
Integer operateUser = (Integer) claims.get("id");
// 操作时间
LocalDateTime operateTime = LocalDateTime.now();
// class name
String className = joinPoint.getTarget().getClass().getName();
// 方法名
String methodName = joinPoint.getSignature().getName();
// 参数
String methodParams = Arrays.toString(joinPoint.getArgs());
// 返回值 将返回值 转陈 json 类型字符串
long begin = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
String resultValue = JSONObject.toJSONString(result);
// 方法 耗时
long costTime = end - begin;
OperateLog operateLog = new OperateLog(null,operateUser,operateTime,className,methodName,methodParams,resultValue,costTime);
operateLogMapper.insert(operateLog);
log.info("AOP中操作日志:{}",operateLog);
return result;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
}
- Log 注解
- aop 根据 @Log 注解 进行包裹.
- 在controller中的 增 删 改 方法前使用@Log 注解标记
@Log
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id){
deptService.delete(id);
log.info("根据日志输出{}",id);
return Result.success();
}
@Log
@PostMapping
public Result add(@RequestBody Dept dept){
log.info("新增部门{}",dept);
deptService.add(dept);
return Result.success();
}

获取注解中的参数
-
指定注解可以接受value 参数, 类型是某个枚举类型
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) // @interface 表示注解 public @interface AutoFill { //UPDATE INSERT // 注解中会出现 @AutoFill(value = ) 等于的值为 OperationType中指定的 OperationType value(); } -
获取参数 在
@Before("@annotation(autoFill)" )中填入注解形参的名字, 函数第二个参数设置log注解即可;@Slf4j @Component @Aspect public class AutoFillAspect { /** * 切入点 */ @Pointcut("@annotation(com.sky.annotation.AutoFill)") public void pt(){}; @Before("@annotation(autoFill)" ) public void AutoFill(JoinPoint joinPoint,AutoFill autoFill) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { log.info("开始执行公共字段填充"); //拦截mapper方法 update操作 只用 updateTime updateUser 赋值即可 // 获取方法的参数实体对象 OperationType operationType = autoFill.value(); log.info("获取到传入value:{}",operationType);