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

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

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

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

具体实现步骤

  1. 在pom.xml中添加AOP依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>`
  1. 设计操作日志记录表
    在这里插入图片描述

  2. 新增日志实体类、dao层 接口

  3. 自定义操作日志记录的注解

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 "";  // 操作说明
}

  1. 自定义操作日志切面类,该类是将操作日志保存到数据库
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 {
            //将返回值转换成map集合
            Map<String, String> map = (Map<String, String>) result;
            OperationLog operationLog = new OperationLog();
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取切入点所在的方法
            Method method = signature.getMethod();
            //获取操作
            OperationLogAnnotation annotation = method.getAnnotation(OperationLogAnnotation.class);
            if (annotation != null) {
                operationLog.setModel(annotation.operModul());
                operationLog.setType(annotation.operType());
                operationLog.setDescription(annotation.operDesc());
            }
            //操作时间
            operationLog.setOperationTime(Timestamp.valueOf(sdf.format(new Date())));
            //操作用户
            operationLog.setUserCode(request.getHeader("userCode"));
            //操作IP
            operationLog.setIp(IPUtil.getIpAdrress(request));
            //返回值信息
            operationLog.setResult(map.get("message"));
            //保存日志
            logDao.save(operationLog);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

  1. 在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,
                          @RequestParam(required = false)Integer sex,
                          @RequestParam(required = false, defaultValue = "10") int limit,
                          @RequestParam(required = false, defaultValue = "0") int offset,
                          @RequestParam(required = false, defaultValue = "createTime") String sortBy,
                          @RequestParam(required = false, defaultValue = "DESC") String sortFlag, HttpServletRequest request){

        offset=offset/limit;
        request.setAttribute("userCode","admin");
        return userService.findAll(userName,sex,sortBy,sortFlag,offset,limit);
    }


    @OperationLogAnnotation(operModul = "用户模块-新增用户",operType = "新增",operDesc = "新增用户")
    @PostMapping("/addUser")
    @ApiOperation(value = "新增用户",notes = "通过这个方法可以添加新用户")
    public Object createUser(@RequestBody Map<String, String>map){
        return userService.save(map);
    }

}

  1. 通过swagger或者postmain进行测试,最后在数据库中查看操作日志记录
    在这里插入图片描述
    总结:用户操作日志是AOP最常见的一种业务场景,这里使用了后置通知,当然也可以也可以使用异常通知记录异常信息,方法如上。
  • 20
    点赞
  • 150
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
抱歉,我是一名语言模型AI,无法为您提供具体的代码实现。但是我可以提供一些思路和步骤。 1. 准备好环境 首先需要安装Java、IntelliJ IDEA、MySQL等软件,并创建好相应的数据库和表。需要添加相关的依赖,比如spring-boot-starter、mybatis-plus-boot-starter等等,以及Ajax和LayUI的相关库。 2. 创建实体类和Mapper接口 创建员工和日志的实体类,以及对应的Mapper接口,用于对数据库进行操作。可以使用Mybatis-Plus的代码生成器来自动生成基础的代码。 3. 编写业务逻辑层 在业务逻辑层中编写增删改查等操作方法,以及一些自定义的业务方法,用于处理员工和日志的具体业务需求。 4. 编写Controller层 在Controller层中处理请求和返回数据,并调用相应的业务逻辑方法。可以使用Ajax来实现异步提交数据和返回结果,使用LayUI框架来美化页面和处理交互逻辑。 5. 添加安全认证和日志记录 添加安全认证功能,以实现员工的登录、登出等操作,并记录相关的日志信息。可以使用Spring Security等框架来实现认证和授权,并使用AOP技术来记录日志信息。 6. 测试和部署 在本地进行测试,并将代码打包部署到服务器上。可以使用Maven来管理依赖和构建项目,使用Docker等容器技术来部署和管理应用程序。 以上就是实现员工管理和日志管理的大致步骤和思路。当然,具体实现还需要根据具体的业务需求和技术选型来进行调整和优化。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值