注解需要的maven坐标:
org.springframework.boot
spring-boot-starter-aop
首先需要了解execution表达式如何书写
eq:execution(public * com.example.druid.controller..*.*(..))
第一个"*" ---------------- 表示匹配任意返回类型
com.example.druid.controller -------------- controller的存放包名,需要替换
.. --------------- 当前包以及子包
第二个"*" --------------- 所有类
第三个"*" ---------------- 所有方法
(..) ----------------- 所有类型的参数,如(int a,int b);(int a)
@Aspect
@Component
@Slf4j
@Order(1)
@Aspect 和 @Component 是必须的,@Slf4j 用来打印日志,@Order(1) 设置切面优先级
在新建的类中新建一个方法,方法名任意取,在方法名上分添加注解如下:
@Pointcut("execution(public * com.example.druid.controller..*.*(..))")
//@Pointcut("@annotation(com.example.druid.annotation.Limit)") 也可以这么使用,添加了注解就会调用,括号里面的值是注解的全路径
pubilc void point(){
}
新建方法,方法名任意,参数是 (JoinPoint joinPoint),然后再在方法上添加注解如下:
@Before("point()") //point换成步骤二中自己取的方法名
public void before(JoinPoint joinPoint){
// 获取请求域
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
// 记录请求内容
log.info("请求开始时间: "+System.currentTimeMillis());
log.info("接口路径: " + request.getRequestURI().toLowerCase());
log.info("请求方式: " + request.getMethod());
log.info("请求者ip: " + request.getRemoteAddr());
log.info("请求方法的类名: " + joinPoint.getSignature().getDeclaringTypeName() );
log.info("请求方法名: "+joinPoint.getSignature().getName());
log.info("传入的参数: " + Arrays.toString(joinPoint.getArgs()));
}
获取该注解所在的方法对象:
Method resolveMethod(JoinPoint point) {
MethodSignature signature = (MethodSignature) point.getSignature();
Class> targetClass = point.getTarget().getClass();
Method method = getDeclaredMethod(targetClass, signature.getName(), signature.getMethod().getParameterTypes());
if (method == null) {
throw new IllegalStateException("无法解析目标方法: " + signature.getMethod().getName());
}
return method;
}
private Method getDeclaredMethod(Class> clazz, String name, Class>... parameterTypes) {
try {
return clazz.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
Class> superClass = clazz.getSuperclass();
if (superClass != null) {
return getDeclaredMethod(superClass, name, parameterTypes);
}
}
return null;
}
@Before 表示,在方法执行前调用,如果你的 controller 中,有参数校验如(@RequestParam(value = "aa",required = true) String aa),若你未传此参数,不会进入方法中,自然不会调用添加了@Before的方法。
新建方法,在方法上添加如下注解:
@After("point()") //point换成步骤二中自己的方法名
public void after(){
log.info("方法结束时间: "+System.currentTimeMillis());
}
@After 表示,在方法执行后调用
新建方法,在方法上添加如下注解:
@AfterReturning(returning = "return", pointcut = "point()")
public void doAfterReturning(Object return) throws Throwable {
log.info("方法返回值: " + return);
}
@AfterReturning 表示,在方法返回结果后调用 ,在@After之前执行
returning属性:将返回值用value接收,方法可以打印或处理value值
新建方法,在方法上添加如下注解:
@AfterThrowing(pointcut = "point()", throwing = "ex")
public void afterReturning(JoinPoint point, Exception ex) {
String methodName = point.getSignature().getName();
List
@AfterThrowing 表示在切入点发生异常后调用