AOP应用之系统操作日志

本文演示下如何使用AOP,去实现系统操作日志功能。

实现步骤

  1. 引入AOP包
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
     <version>2.6.6</version>
 </dependency>
  1. 定义数据模型
package com.angel.ocean.domain.entity;

import lombok.Data;
import java.util.Date;

@Data
public class Syslog {
    /**
     * 主键
     **/
    private Long id;
    /**
     * ip 地址
     **/
    private String ip;
    /**
     * 类名
     **/
    private String className;
    /**
     * 方法名称
     **/
    private String methodName;
    /**
     * 传参
     **/
    private String params;
    /**
     * 执行结果, true-成功,false-失败
     **/
    private boolean status;
    /**
     * 响应信息
     **/
    private String response;
    /**
     * 业务类型
     **/
    private String remark;
    /**
     * 触发时间
     **/
    private Date createTime;
    /**
     * 操作用户
     **/
    private String createBy;
}
  1. 定义系统日志注解SyslogAnno
package com.angel.ocean.annotation;

import java.lang.annotation.*;

/**
 * 定义系统日志注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SyslogAnno {

    String value() default "";

}
  1. 定义切面SyslogAspect
package com.angel.ocean.aspect;

import com.alibaba.fastjson2.JSON;
import com.angel.ocean.annotation.SyslogAnno;
import com.angel.ocean.domain.entity.Syslog;
import com.angel.ocean.runner.SyslogHandlerTask;
import com.angel.ocean.util.LogDataUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 1. 日志切面
 */
@Slf4j
@Aspect
@Component
public class SyslogAspect {

    @Pointcut("@annotation(com.angel.ocean.annotation.SyslogAnno)")
    public void logPointCut() {
    }

    @AfterReturning(value = "logPointCut()", returning = "result")
    public void normalLog(JoinPoint point, Object result) {
        try {
            Syslog syslog = getSysLog(point);
            syslog.setStatus(true);
            syslog.setResponse(JSON.toJSONString(result));
            SyslogHandlerTask.LOG_QUEUE.offer(syslog);
        } catch (Exception e) {
            log.error("SyslogAspect.normalLog() error. ", e);
        }
    }

    @AfterThrowing(value = "logPointCut()", throwing = "throwable")
    public void exceptionLog(JoinPoint point, Throwable throwable) {
        try {
            Syslog syslog = getSysLog(point);
            syslog.setStatus(false);
            syslog.setResponse(throwable.getMessage());
            SyslogHandlerTask.LOG_QUEUE.offer(syslog);
        } catch (Exception e) {
            log.error("SyslogAspect.exceptionLog() error. ", e);
        }
    }

    private Syslog getSysLog(JoinPoint joinPoint) {

        Syslog sysLog = new Syslog();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        SyslogAnno sysLogAnno = method.getAnnotation(SyslogAnno.class);
        if (sysLogAnno != null) {
            sysLog.setRemark(sysLogAnno.value());
        }

        // 请求的 类名、方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setClassName(className);
        sysLog.setMethodName(methodName);

        // 请求的参数
        Object[] args = joinPoint.getArgs();
        try {
            List<String> list = new ArrayList<>();
            for (Object o : args) {
                list.add(JSON.toJSONString(o));
            }
            sysLog.setParams(list.toString());
        } catch (Exception e) {
            log.error("SyslogAspect.saveLog() error.", e);
        }

        sysLog.setIp(LogDataUtil.getIP());
        sysLog.setCreateBy(LogDataUtil.getUserId());
        sysLog.setCreateTime(new Date());

        return sysLog;
    }
}

工具类

package com.angel.ocean.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

@Slf4j
public class LogDataUtil {

    private LogDataUtil() {}

    /**
     *  获取用户IP地址
     */
    public static String getIP() {
        String ip = "";
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            ip = request.getRemoteAddr();
        } catch (Exception e) {
            log.error("GetIPException", e);
        }
        return ip;
    }

    /**
     * 获取用户ID
     */
    public static String getUserId() {
        String userId = "";
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            userId = request.getHeader("userId");
        } catch (Exception e) {
            log.error("GetUserIdException", e);
        }
        return userId;
    }
}
  1. 定义日志数据处理SyslogHandlerTask
package com.angel.ocean.runner;

import cn.hutool.core.collection.CollUtil;
import com.angel.ocean.domain.entity.Syslog;
import com.angel.ocean.service.SyslogService;
import com.google.common.collect.Queues;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class SyslogHandlerTask implements CommandLineRunner {

    @Resource
    private SyslogService syslogService;

    /**
     * 操作日志队列
     */
    public static final BlockingQueue<Syslog> LOG_QUEUE = new LinkedBlockingQueue<>();

    @Override
    public void run(String... strings) throws Exception {
        new Thread(() -> {
            List<Syslog> SyslogList = new ArrayList<>();
            while (true) {
                try {
                    Queues.drain(LOG_QUEUE, SyslogList, 100, 500, TimeUnit.MILLISECONDS);
                    if (CollUtil.isNotEmpty(SyslogList)) {
                        syslogService.batchInsert(SyslogList);
                        SyslogList.clear();
                    } else {
                        Thread.sleep(500);
                    }
                } catch (Exception e) {
                    log.error("SyslogHandlerTask error={}", e.getMessage(), e);
                }
            }
        }, "Syslog_Props_Mysql").start();
    }
}
  1. 打包成系统操作日志SDK (ocean-log)

如何使用

继承系统操作日志SDK

<dependency>
    <groupId>com.angel.ocean</groupId>
    <artifactId>ocean-log</artifactId>
    <version>1.0.0</version>
</dependency>

在Api的添加/修改/删除等方法上,添加SyslogAnno注解

@ApiModelProperty(value = "保存角色信息表")
@PostMapping("save")
@SyslogAnno("添加角色")
public ApiResult<?> save(@RequestBody SysRoleDTO dto) {
    service.save(dto);
    return ApiResult.success();
}

实例验证

接口调用
在这里插入图片描述系统操作日志数据
在这里插入图片描述

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值