<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
package com.shenma2009.log;
import java.lang.annotation.*;
/**
* @author 军哥
* @version 1.0
* @description: 自定义注解
* @date 2023/6/7 8:57
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface SmLog {
// 日志标识
String value() default "sm";
// 日志级别
String level() default "info";
}
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
**取值(ElementType)有:**
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
**取值(RetentionPoicy)有:**
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
package com.shenma2009.log;
import com.alibaba.fastjson2.JSON;
import com.shenma2009.domain.ResultResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
/**
* @author 军哥
* @version 1.0
* @description: SmLogAspect
* @date 2023/6/7 9:01
*/
@Aspect
@Component
public class SmLogAspect {
@Pointcut("@annotation(com.shenma2009.log.SmLog)")
public void smLogPointCut() {}
/**
* @description 后置通知
* @author 军哥
* @date 2023/6/7 9:12
* @version 1.0
*/
@AfterReturning(value = "smLogPointCut()", returning = "returnValue")
public void doAfterReturning(JoinPoint point, Object returnValue){
MethodSignature signature = (MethodSignature) point.getSignature();
// 获取方法名
String methodName = signature.getName();
// 获取参数
List<Object> args = Arrays.asList(point.getArgs());
Method method = signature.getMethod();
SmLog annotation = method.getAnnotation(SmLog.class);
System.out.println("后置通知 => value:"+annotation.value());
System.out.println("后置通知 => level:"+annotation.level());
System.out.println("后置通知 => 方法为:" + methodName + ",参数为:" + JSON.toJSONString(args) + ",返回值为:" + JSON.toJSONString(returnValue));
}
/**
* @description 前置通知
* @author 军哥
* @date 2023/6/7 15:17
* @version 1.0
*/
@Before(value = "execution(* com.shenma2009.controller.IndexController.insertSmLog(..))")
public void doBefore(JoinPoint point) throws Exception {
MethodSignature signature = (MethodSignature) point.getSignature();
// 获取注解信息
Method method = signature.getMethod();
SmLog annotation = method.getAnnotation(SmLog.class);
System.out.println("前置通知 => value:"+annotation.value());
System.out.println("前置通知 => level:"+annotation.level());
// 检查权限
if(!annotation.value().equals("insert")) {
throw new Exception("权限不足");
}
System.out.println("前置通知 => 权限合法");
}
/**
* @description 环绕通知
* @author 军哥
* @date 2023/6/7 14:53
* @version 1.0
*/
// 第一种方式
@Around("@annotation(com.shenma2009.log.SmLog)")
// 第二种表达式
//@Around(value = "smLogPointCut()")
public Object doAround(ProceedingJoinPoint point) throws Throwable {
//获取方法参数
Object[] args = point.getArgs();
System.out.println("环绕通知 => 参数为:" + JSON.toJSONString(args));
ResultResponse ret = (ResultResponse) point.proceed();
if(ret.getCode() == 200){
//code=1,说明操纵成功
System.out.println("环绕通知 => 操纵成功");
return ret;
}
//操作失败返回Result的执行结果
System.out.println("环绕通知 => 操纵失败");
return ret;
}
//设置抛出异常后通知获取原始方法运行时抛出的异常对象,要求throwing属性值必须与方法形参名相同
@AfterThrowing(value = "smLogPointCut()",throwing = "t")
public void afterThrowing(Throwable t) {
System.out.println("异常通知 => "+JSON.toJSONString(t));
}
}
package com.shenma2009.controller;
import com.shenma2009.domain.ResultResponse;
import com.shenma2009.log.SmLog;
import com.shenma2009.vo.IdVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
* @author 军哥
* @version 1.0
* @description: IndexController
* @date 2023/6/7 9:20
*/
@RestController
@RequestMapping(value = "/index")
@Slf4j
public class IndexController {
@PostMapping(value = "listRandSmLog/{id}")
@SmLog(value = "test", level = "debug")
public ResultResponse listRandSmLog(@PathVariable("id") Integer id) {
log.info("id="+id);
return ResultResponse.SUCCESS(id);
}
@PostMapping(value = "/insertSmLog")
@SmLog(value = "insert", level = "info")
public ResultResponse insertSmLog(@RequestBody IdVo idVo) {
log.info("id="+idVo.getId());
return ResultResponse.SUCCESS(idVo);
}
@PostMapping(value = "/throwError")
@SmLog(value = "insert", level = "info")
public ResultResponse throwError() {
String msg = null;
System.out.println(msg.length());
return ResultResponse.SUCCESS();
}
}