AOP案例-记录日志操作

目录

案例

操作日志

思路分析

步骤

准备

编码


案例

  • 将案例中的增删改接口的操作日志记录到数据表中

操作日志

  • 日志信息包括:操作人、操作时间、执行方法的全类名、执行方法名、方法运行时的参数、返回值、犯法运行时长。

思路分析

  • 需要对于所有业务类中的增删改查方法统一添加功能,使用AOP技术最方便,@Around环绕通知
  • 由于增删改方法名命名不规律,可以自定义@Log注解完成目标方法的匹配

步骤

准备

  • 引入AOP的起步依赖
  • 导入资料中准备好的数据表结构,并引入对应的实体类
    • 数据结构表
      • -- 操作日志表
        create table operate_log(
                                    id int unsigned primary key auto_increment comment 'ID',
                                    operate_user int unsigned comment '操作人ID',
                                    operate_time datetime comment '操作时间',
                                    class_name varchar(100) comment '操作的类名',
                                    method_name varchar(100) comment '操作的方法名',
                                    method_params varchar(1000) comment '方法参数',
                                    return_value varchar(2000) comment '返回值',
                                    cost_time bigint comment '方法执行耗时, 单位:ms'
        ) comment '操作日志表';
        
        
        
        
    • 实体类(用于封装操作日志信息)

      • package com.example.tlias.pojo;
        
        import lombok.AllArgsConstructor;
        import lombok.Data;
        import lombok.NoArgsConstructor;
        
        import java.time.LocalDateTime;
        
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        public class OperateLog {
            private Integer id; //ID
            private Integer operateUser; //操作人ID
            private LocalDateTime operateTime; //操作时间
            private String className; //操作类名
            private String methodName; //操作方法名
            private String methodParams; //操作方法参数
            private String returnValue; //操作方法返回值
            private Long costTime; //操作耗时
        }
        

编码

  • 自定义注解@Log
    • package com.example.tlias.Anno;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      
      @Retention(RetentionPolicy.RUNTIME) // todo 设置该疏解的生效时间
      @Target(ElementType.METHOD) // todo 设置该注解可以作用在方法上
      public @interface Log {
      }
      
  • 定义切面类,完成记录操作日志的逻辑
    • package com.example.tlias.AOP;
      
      import com.alibaba.fastjson.JSONObject;
      import com.example.tlias.mapper.OperateLogMapper;
      import com.example.tlias.pojo.OperateLog;
      import com.example.tlias.utils.JwtUtils;
      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.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Component;
      
      import java.time.LocalDateTime;
      import java.util.Arrays;
      
      @Component
      @Aspect // todo 表名当前类是一个切面类
      @Slf4j
      public class LogAspect {
          @Autowired
          private OperateLogMapper operateLogMapper;
      
          // todo 注入当前请求的请求对象
          @Autowired
          private HttpServletRequest request;
      
          // todo 定义通知方法
          @Around("@annotation(com.example.tlias.Anno.Log)")  // todo 使用注解的方法设置切入点
          public Object LogAspect(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
              // todo 获取操作人的id--即当前登录员工的id
              // 获取请求头中的JWT令牌,解析令牌就可获取登录员工的ID
              String jwt = request.getHeader("token");
              // 使用之前编写好的解析JWT令牌的工具类来解析获取到的JWT令牌
              Claims claims = JwtUtils.parseJWT(jwt);
              Integer OperateUserID = (Integer) claims.get("id");
              // todo 获取操作类名
              String ClassName = proceedingJoinPoint.getTarget().getClass().getName();
              // todo 获取操作时间
              LocalDateTime OperateTime = LocalDateTime.now();
              // todo 获取操方法名
              String MethodName = proceedingJoinPoint.getSignature().getName();
              // todo 获取操作方法参数
              Object[] args = proceedingJoinPoint.getArgs();
              // 将数组类型数据转换为字符串类型
              String MethodParams = Arrays.toString(args);
              // todo 获取操作方法运行开始时间
              // 先获取开始时间,方法运行完成之后再获取结束时间
              Long start = System.currentTimeMillis();
              // todo 获取操作方法返回值
              // 调用原始目标方法运行
              Object result = proceedingJoinPoint.proceed();
              // 将对象专为JSON格式数据的字符串,仍然使用工具包JSONFast
              String returnValue = JSONObject.toJSONString(result);
              // todo 获取操作方法运行结束时间
              Long end = System.currentTimeMillis();
              // 计算方法运行耗时
              Long coatTime = end - start;
              // todo 使用全参构造,完成数据的封装
              OperateLog operateLog = new OperateLog(null, OperateUserID, OperateTime, ClassName, MethodName, MethodParams, returnValue, coatTime);
              // todo 向operateLog对象中封装相关信息
      //        operateLog.setClassName(ClassName);
      //        operateLog.setCostTime(coatTime);
      //        operateLog.setMethodName(MethodName);
      //        operateLog.setMethodParams(MethodParams);
      //        operateLog.setOperateTime(OperateTime);
      //        operateLog.setOperateUser(OperateUserID);
      //        operateLog.setReturnValue(returnValue);
      //        operateLogMapper.insert(operateLog);
              // todo 完成日志数据的记录
              operateLogMapper.insert(operateLog);
      
              log.info("AOP记录操作日志", operateLog);
              return result;
          }
      
      }
      

  • 获取当前登录用户
    • 获取request对象,从请求头中获取JWT令牌,解析令牌获取当前用户ID 

你可能感兴趣的:(Java,Web学习跟踪笔记,java,数据库,开发语言)