AOP实现操作日志记录

Spring的aop切面编程技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志。

依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

日志实体类

1
2
3
4
5
6
7
8
9
10
11
public class Record implements Serializable {

private Long id;

private String userName; //用户名

private String operation; //操作

private Date createDate; //操作时间

}

自定义注解类

1
2
3
4
5
6
7
8
9
10
11
import java.lang.annotation.*;

/**
* 自定义注解类
*/
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface MyRecord {
String value() default "";
}

创建aop切面实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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 javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
* 系统日志:切面处理类
*/
@Aspect
@Component
public class RecordAspect {

@Autowired
private RecordService recordService;

//定义切点 @Pointcut
//在注解的位置切入代码
@Pointcut("@annotation( com.example.record.MyRecord)")
public void logPoinCut() {
}

//切面 配置通知
@AfterReturning("logPoinCut()")
public void saveRecord(JoinPoint joinPoint) {

System.out.println("切面。。。。。");
//保存日志
Record record = new Record();

//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();

//获取操作
MyRecord myRecord = method.getAnnotation(MyRecord.class);
if (myRecord != null) {
String value = myRecord.value();
sysLog.setOperation(value);//保存获取的操作
}

record.setCreateDate(new Date());
//获取用户名
record.setUsername(ShiroUtils.getUserEntity().getUsername());

//调用service保存SysLog实体类到数据库
recordService.save(record);
}

}

在需要监控的方法上添加 aop的自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//例如在contoller类的方法上加注解
@RestController
@RequestMapping("/sys/menu")
public class SysMenuController extends AbstractController {

@Autowired
private SysMenuService sysMenuService;

@MyRecord(value = "删除菜单记录") //这里添加了AOP的自定义注解
@PostMapping("/del")
public R deleteBatch(@RequestBody Long[] menuIds) {
for (Long menuId : menuIds) {
if (menuId <= 31) {
return R.error("系统菜单,不能删除");
}
}
sysMenuService.deleteBatch(menuIds);

return R.ok("删除成功");
}
}