SpringBoot+AOP实现用户操作日志的记录

蔚落 2023-10-05 10:43 176阅读 0赞

前言:
任何一个项目都会有一个用户操作日志(也叫行为日志)的模块,它主要用来记录某个用户做了某个操作,当出现操作失败时,通过日志就可以快速的查找是哪个用户在哪个模块出现了错误,以便于开发人员快速定位问题所在。

实现这一功能一般有两种方法:

  • 第一种就是很传统的做法,就是在每个模块进行插入日志的操作(不推荐),这种做法虽然实现了记录用户的操作,但很繁琐而且基本上是重复的工作。
  • 第二种就是使用Spring的AOP来实现记录用户操作,也是推荐的现如今都使用的一种做法。它的优势在于这种记录用户操作的代码独立于其他业务逻辑代码,不仅实现了解耦,而且避免了冗余代码。

具体实现步骤

  1. 在pom.xml中添加AOP依赖

    1. <groupId>org.springframework.boot</groupId>
    2. <artifactId>spring-boot-starter-aop</artifactId>
    3. </dependency>`
  2. 设计操作日志记录表
    在这里插入图片描述

  3. 新增日志实体类、dao层 接口
  4. 自定义操作日志记录的注解

    package com.example.springcloud.aop;

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;

    /**

    • @author lyz
    • @title: OperationLog
    • @projectName springcloud
    • @date 2020/9/23
    • @description: 自定义操作日志注解
      */
      @Target(ElementType.METHOD)//注解放置的目标位置即方法级别
      @Retention(RetentionPolicy.RUNTIME)//注解在哪个阶段执行
      @Documented
      public @interface OperationLogAnnotation {

      String operModul() default “”; // 操作模块

      String operType() default “”; // 操作类型

      String operDesc() default “”; // 操作说明
      }

  5. 自定义操作日志切面类,该类是将操作日志保存到数据库

    package com.example.springcloud.aop;

    import com.example.springcloud.dao.OperationLogDao;
    import com.example.springcloud.domain.OperationLog;
    import com.example.springcloud.utils.IPUtil;
    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 org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;

    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.sql.Timestamp;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Map;

    /**

    • @author lyz
    • @title: OperationAspect
    • @projectName springcloud
    • @date 2020/9/23
    • @description: 操作日志切面处理类
      */
      @Aspect
      @Component
      public class OperationLogAspect {

      @Autowired
      OperationLogDao logDao;
      private static SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

      /**

      • 设置操作日志切入点 在注解的位置切入代码
        */
        @Pointcut(“@annotation(com.example.springcloud.aop.OperationLogAnnotation)”)
        public void operLogPoinCut() {

        }

        /**

      • 记录操作日志
      • @param joinPoint 方法的执行点
      • @param result 方法返回值
      • @throws Throwable
        */
        @AfterReturning(returning = “result”, value = “operLogPoinCut()”)
        public void saveOperLog(JoinPoint joinPoint, Object result) throws Throwable {

        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        try {

        1. //将返回值转换成map集合
        2. Map<String, String> map = (Map<String, String>) result;
        3. OperationLog operationLog = new OperationLog();
        4. // 从切面织入点处通过反射机制获取织入点处的方法
        5. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        6. //获取切入点所在的方法
        7. Method method = signature.getMethod();
        8. //获取操作
        9. OperationLogAnnotation annotation = method.getAnnotation(OperationLogAnnotation.class);
        10. if (annotation != null) {
        11. operationLog.setModel(annotation.operModul());
        12. operationLog.setType(annotation.operType());
        13. operationLog.setDescription(annotation.operDesc());
        14. }
        15. //操作时间
        16. operationLog.setOperationTime(Timestamp.valueOf(sdf.format(new Date())));
        17. //操作用户
        18. operationLog.setUserCode(request.getHeader("userCode"));
        19. //操作IP
        20. operationLog.setIp(IPUtil.getIpAdrress(request));
        21. //返回值信息
        22. operationLog.setResult(map.get("message"));
        23. //保存日志
        24. logDao.save(operationLog);

        } catch (Exception e) {

        1. e.printStackTrace();

        }
        }

    }

  6. 在controller层的某一个方法加入@OperationLogAnnotation 注解

    package com.example.springcloud.controller;

    import com.example.springcloud.aop.OperationLogAnnotation;
    import com.example.springcloud.domain.User;
    import com.example.springcloud.service.UserService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpRequest;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;

    import javax.servlet.http.HttpServletRequest;
    import java.util.Map;

    /**

    • @author lyz
    • @title: UserController
    • @projectName springcloud
    • @date 2020/9/12
    • @description:
      */
      @Api(tags = “用户表”)
      @RestController
      @RequestMapping(“/user”)
      public class UserController {

      @Autowired
      UserService userService;

      @OperationLogAnnotation(operModul = “用户模块-用户列表”,operType = “查询”,operDesc = “查询所有用户”)
      @ApiOperation(value = “查询所有用户”,notes = “这是用来查询所有用户列表”)
      @GetMapping(“/users”)
      public Object findAll(@RequestParam(required = false)String userName,

      1. @RequestParam(required = false)Integer sex,
      2. @RequestParam(required = false, defaultValue = "10") int limit,
      3. @RequestParam(required = false, defaultValue = "0") int offset,
      4. @RequestParam(required = false, defaultValue = "createTime") String sortBy,
      5. @RequestParam(required = false, defaultValue = "DESC") String sortFlag, HttpServletRequest request){
  1. offset=offset/limit;
  2. request.setAttribute("userCode","admin");
  3. return userService.findAll(userName,sex,sortBy,sortFlag,offset,limit);
  4. }
  5. @OperationLogAnnotation(operModul = "用户模块-新增用户",operType = "新增",operDesc = "新增用户")
  6. @PostMapping("/addUser")
  7. @ApiOperation(value = "新增用户",notes = "通过这个方法可以添加新用户")
  8. public Object createUser(@RequestBody Map<String, String>map){
  9. return userService.save(map);
  10. }
  11. }
  1. 通过swagger或者postmain进行测试,最后在数据库中查看操作日志记录
    在这里插入图片描述
    总结:用户操作日志是AOP最常见的一种业务场景,这里使用了后置通知,当然也可以也可以使用异常通知记录异常信息,方法如上。

发表评论

表情:
评论列表 (有 0 条评论,176人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Spring boot实现AOP记录操作

    前言 在实际的项目中,特别是管理系统中,对于那些重要的操作我们通常都会记录操作日志。比如对数据库的`CRUD`操作,我们都会对每一次重要的操作进行记录,通常的做法是向数据

    相关 SpringBoot+AOP实现用户操作记录

    前言: 任何一个项目都会有一个用户操作日志(也叫行为日志)的模块,它主要用来记录某个用户做了某个操作,当出现操作失败时,通过日志就可以快速的查找是哪个用户在哪个模块出现了错

    相关 Spring boot实现AOP记录操作

    前言 在实际的项目中,特别是管理系统中,对于那些重要的操作我们通常都会记录操作日志。比如对数据库的CRUD操作,我们都会对每一次重要的操作进行记录,通常的做法是向数据库指定