使用 Spring AOP特性实现的操作日志功能

概述

同前面 SpringSecurity 的学习记录博文一样,在此次项目之中就有这样一个需求,于是我第一时间想到利用 AOP 去解决这件事。

那么我们可以回顾一下 AOP 是什么。它指的是「面向切面」是 Spring 之中的一个很强大的特性,并且在 Spring 的很多东西都是由此为基础去实现的,比如我们经常用到的「拦截器」。简单的来说,就是我们想去实现一些功能,但又不想改变代码原有的结构,比如我们想在某个 controller 的接口结束之后自动做某些操作啦,或在其执行之前做什么操作。

这些都可以依靠 AOP 进行实现。

实现

pom

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

代码

首先,我们的需求是某些操作执行完毕之后去记录一下,那么我们必然需要知道它是干什么的,我们该如何得知呢?如果是前面所学的 before 或 after 似乎都无法实现这样一个需求。

所以我们想我们可以去实现一个注解,然后使用注解去标注其值,我们只需要获取到注解之内的值就可以了~

注解

于是我创建了一个名为「OperLog」的注解。主要在方法之上使用,并且拥有三个参数来进行阐述该功能的信息。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperLog {
    String operModul() default ""; // 操作模块
    String operType() default "";  // 操作类型
    String operDesc() default "";  // 操作说明
}

其后,我们可以直接使用它在某些模块上进行展示。见下面代码。

@PostMapping("/xxxx/xxx")
@ResponseResult
@OperLog(operModul = "设置模块",operType = "常规配置修改",operDesc = "后台修改常规配置")
public void setxxxxxConfig(@RequestBody JSONObject jsonObject) {

切面类

然后我们需要创建一个名为「OperLogAspect」的切面类。需要加上注解「@Aspect」声明其是切面类,然后将其注册为组件。

@Aspect
@Component
public class OperLogAspect {

之后我们通过注解来实现一个切入点。

@Pointcut("@annotation(com.xxx.annotations.OperLog)")
public void operLogPoinCut() {
}

然后使用这个切入点。使用「joinPoint」参数获取对应的方法,然后通过方法获取我们的注解,再通过注解去获得我们上述在模块之上记录的模块相关的信息,然后使用自己定义的「logService」将其存入 Redis 之中。

「@AfterReturning」注解实际上还可以获取对应方法的返回值,不过我们并没有用到,只是为了学习所以才这样使用。

@AfterReturning(value = "operLogPoinCut()", returning="returnValue")
public void saveOperLog(JoinPoint joinPoint, Object returnValue) {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    OperLog opLog = method.getAnnotation(OperLog.class);
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
    String Authorization = request.getHeader("Authorization");
    String username = JwtUtils.getUsername(Authorization);
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("operModul", opLog.operModul());
    jsonObject.put("operType", opLog.operType());
    jsonObject.put("operDesc", opLog.operDesc());
    jsonObject.put("userName", username);
    jsonObject.put("date", new Date());
    logService.addLog(jsonObject);
}
# SpringAOP