业务需求-用AOP记录系统操作日志

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 全栈老司机 程序员林中酒 更新了本文详细介绍了如何使用AOP(面向切面编程)记录系统操作日志的业务需求,包括需求分析、技术实现分析、数据库设计和代码实现等各个环节。您将了解如何高效、规范地实现这一功能

嗨嗨嗨 全栈老司机 程序员林中酒(公众号同名) 来啦

业务分析

需求分析

要记录用户调用后端服务的每一次系统日志

技术实现分析

用Aop实现每次调用接口时记录相关信息

数据库设计

create table ***.s_api_log
(
    id          int auto_increment comment 'ID'
        primary key,
    ip          varchar(255)     null comment 'IP地址',
    uri         varchar(255)     null comment '请求地址',
    user_name   varchar(255)     null comment '用户名称',
    name        varchar(50)      null comment '操作名称',
    method      varchar(255)     null comment '请求方法',
    params      varchar(255)     null comment '请求参数',
    result      varchar(255)     null comment '返回结果',
    time        bigint           null comment '响应时间',
    ct          varchar(255)     null comment '创建时间',
    type        varchar(50)      null comment '操作类型',
    description varchar(255)     null comment '操作描述',
    del_flge    bit default b'0' not null comment '删除标记 0:未删除 1:已删除'
)
    comment '接口日志表' collate = utf8mb4_bin
                         row_format = DYNAMIC;

代码

1. 所需依赖

<!--      AOP切面编程-->  
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-aop</artifactId>  
</dependency>  
<!-- END     AOP切面编程-->

<!-- hutool工具包 -->  
<dependency>  
    <groupId>cn.hutool</groupId>  
    <artifactId>hutool-all</artifactId>  
    <version>5.8.3</version>  
</dependency>  
<!--END hutool工具包 -->

<!-- mybatis-plus -->  
<dependency>  
    <groupId>com.baomidou</groupId>  
    <artifactId>mybatis-plus-boot-starter</artifactId>  
    <version>3.4.1</version>  
</dependency>

2. 数据库实体类-ApiLog

package com.linzhongjiu.common.web.system.entity;  

import com.baomidou.mybatisplus.annotation.IdType;  
import com.baomidou.mybatisplus.annotation.TableId;  
import java.io.Serializable;  

import com.baomidou.mybatisplus.annotation.TableName;  
import lombok.Data;  
import lombok.EqualsAndHashCode;  

/**  
 * <p>  
 * 操作日志表  
 * </p>  
 * @since 2024-01-11  
 */@Data  
@EqualsAndHashCode(callSuper = false)  
@TableName("s_api_log")  
public class ApiLog implements Serializable {  

    private static final long serialVersionUID = 1L;  

    /**  
     * ID     */    @TableId(value = "id", type = IdType.AUTO)  
    private Integer id;  

    /**  
     * IP地址  
     */  
    private String ip;  

    /**  
     * 请求地址  
     */  
    private String uri;  

    /**  
     * 请求类型  
     */  
    private String type;  
    /**  
     * 请求名称  
     */  
    private String name;  
    /**  
     * 请求描述  
     */  
    private String description;  

    /**  
     * 用户名称  
     */  
    private String userName;  

    /**  
     * 请求方法  
     */  
    private String method;  

    /**  
     * 请求参数  
     */  
    private String params;  

    /**  
     * 返回结果  
     */  
    private String result;  

    /**  
     * 响应时间  
     */  
    private Long time;  

    /**  
     * 创建时间  
     */  
    private String ct;  

    /**  
     * 删除标记  
     * 0-未删除 1-已删除  
     */  
    private Boolean delFlag;  


}

3. Mapper 层-ApiLogMapper

package com.linzhongjiu.common.web.system.mapper;  

import com.linzhongjiu.common.web.system.entity.ApiLog;  
import com.baomidou.mybatisplus.core.mapper.BaseMapper;  

/**  
 * <p>  
 * 操作日志表 Mapper 接口  
 * </p>  
 *  
 * @since 2024-01-11  
 */public interface ApiLogMapper extends BaseMapper<ApiLog> {  

}

4. Service 层- IApiLogService

package com.linzhongjiu.common.web.system.service;  

import com.linzhongjiu.common.web.system.entity.ApiLog;  
import com.baomidou.mybatisplus.extension.service.IService;  

/**  
 * <p>  
 * 操作日志表 服务类  
 * </p>  
 *  
 * @author linzhongjiu  
 * @since 2024-01-11  
 */public interface IApiLogService extends IService<ApiLog> {  

}

5. 工具类-CommonUtil

public class CommonUtil {  

    /**  
     * 创建时间更新时间  
     *  
     * @return yyyy-MM-dd HH:mm:ss  
     */    
     public static String CtUt() {  
        return DateUtil.formatDateTime(DateUtil.date(System.currentTimeMillis()));  
    }
}

6. 定义注解-OperationLog

package com.linzhongjiu.common.aop.note;  


import java.lang.annotation.*;  


@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上  
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行  
@Documented //生成文档  
public @interface OperationLog {  
    String type() default "OP";//操作类型 LN-登录日志  OP-操作日志  
    String name() default "";//操作名称  
    String description() default "";//操作描述  
}

7. 编写切面-OperationLogAspect

package com.linzhongjiu.common.aop.handle;  

import com.alibaba.fastjson.JSON;  
import com.google.gson.Gson;  
import com.linzhongjiu.common.aop.note.OperationLog;  
import com.linzhongjiu.common.utils.CommonUtil;  
import com.linzhongjiu.common.web.system.entity.ApiLog;  
import com.linzhongjiu.common.web.system.service.IApiLogService;  
import lombok.extern.slf4j.Slf4j;  
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.ProceedingJoinPoint;  
import org.aspectj.lang.annotation.*;  

import org.springframework.core.annotation.Order;  
import org.springframework.stereotype.Component;  
import org.springframework.web.context.request.RequestContextHolder;  
import org.springframework.web.context.request.ServletRequestAttributes;  

import javax.annotation.Resource;  
import javax.servlet.http.HttpServletRequest;  
import java.util.Arrays;  

@Aspect//这个注解的作用是:将一个类定义为一个切面类  
@Component//这个注解的作用:把切面类加入到IOC容器中  
@Order(1)//这个注解的作用是:标记切面类的处理优先级,i值越小,优先级别越高.PS:可以注解类,也能注解到方法上  
@Slf4j  
public class OperationLogAspect {  

    @Resource  
    private IApiLogService apiLogService;  

    private Gson gson = new Gson();  

    //申明一个切点 里面是@annotation  
    @Pointcut("@annotation(operationLog)")  
    public  void annotationPointCut(OperationLog operationLog) {  

    }  
    @Around("annotationPointCut(operationLog)")  
    public void arounding(ProceedingJoinPoint joinPoint, OperationLog operationLog) {  
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();  
        HttpServletRequest request = requestAttributes.getRequest();  
        String path = request.getRequestURL() == null ? "" :request.getRequestURL().toString();  
        ApiLog apiLog = new ApiLog();  
        apiLog.setType(operationLog.type());  
        apiLog.setName(operationLog.name());  
        apiLog.setDescription(operationLog.description());  
        apiLog.setUri(path);  
        apiLog.setMethod(request.getMethod());  
        apiLog.setParams(gson.toJson(request.getParameterMap()));  
        apiLog.setIp(request.getRemoteAddr());  
        apiLog.setUserName(request.getRemoteUser());  
        apiLog.setCt(CommonUtil.CtUt());  

        Object result = null;  
        long beginTime = System.currentTimeMillis();  
        try {  
            // 执行方法  
            result = joinPoint.proceed();  
        } catch (Throwable e) {  
            e.printStackTrace();  
        }  
        // 执行时长(毫秒)  
        long time = System.currentTimeMillis() - beginTime;  
        apiLog.setTime(time);  
        apiLog.setResult(JSON.toJSONString(result));  
        apiLogService.save(apiLog);  
    }  

}

知识点

AOP

  1. @Aspect: 用于定义一个切面,类似于 Java 中的类定义。

  2. @Pointcut: 用于定义一个切入点,表示在哪些连接点上应用切面的通知。

  3. @Before: 在目标方法执行前执行的通知。

  4. @After: 在目标方法执行后(无论正常返回还是异常返回)执行的通知。

  5. @AfterReturning: 在目标方法正常返回后执行的通知。

  6. @AfterThrowing: 在目标方法抛出异常后执行的通知。

  7. @Around: 环绕通知,包围目标方法执行。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
4月前
|
存储 数据采集 数据处理
【Flume拓扑揭秘】掌握Flume的四大常用结构,构建强大的日志收集系统!
【8月更文挑战第24天】Apache Flume是一个强大的工具,专为大规模日志数据的收集、聚合及传输设计。其核心架构包括源(Source)、通道(Channel)与接收器(Sink)。Flume支持多样化的拓扑结构以适应不同需求,包括单层、扇入(Fan-in)、扇出(Fan-out)及复杂多层拓扑。单层拓扑简单直观,适用于单一数据流场景;扇入结构集中处理多源头数据;扇出结构则实现数据多目的地分发;复杂多层拓扑提供高度灵活性,适合多层次数据处理。通过灵活配置,Flume能够高效构建各种规模的数据收集系统。
96 0
|
18天前
|
存储 监控 安全
什么是事件日志管理系统?事件日志管理系统有哪些用处?
事件日志管理系统是IT安全的重要工具,用于集中收集、分析和解释来自组织IT基础设施各组件的事件日志,如防火墙、路由器、交换机等,帮助提升网络安全、实现主动威胁检测和促进合规性。系统支持多种日志类型,包括Windows事件日志、Syslog日志和应用程序日志,通过实时监测、告警及可视化分析,为企业提供强大的安全保障。然而,实施过程中也面临数据量大、日志管理和分析复杂等挑战。EventLog Analyzer作为一款高效工具,不仅提供实时监测与告警、可视化分析和报告功能,还支持多种合规性报告,帮助企业克服挑战,提升网络安全水平。
|
1月前
|
存储 Linux Docker
centos系统清理docker日志文件
通过以上方法,可以有效清理和管理CentOS系统中的Docker日志文件,防止日志文件占用过多磁盘空间。选择合适的方法取决于具体的应用场景和需求,可以结合手动清理、logrotate和调整日志驱动等多种方式,确保系统的高效运行。
52 2
|
1月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
47 1
|
2月前
|
XML JSON 监控
告别简陋:Java日志系统的最佳实践
【10月更文挑战第19天】 在Java开发中,`System.out.println()` 是最基本的输出方法,但它在实际项目中往往被认为是不专业和不足够的。本文将探讨为什么在现代Java应用中应该避免使用 `System.out.println()`,并介绍几种更先进的日志解决方案。
61 1
|
2月前
|
监控 网络协议 安全
Linux系统日志管理
Linux系统日志管理
60 3
|
2月前
|
监控 应用服务中间件 网络安全
#637481#基于django和neo4j的日志分析系统
#637481#基于django和neo4j的日志分析系统
39 4
|
4月前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
142 1
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
2月前
|
监控 Linux 测试技术
Linux系统命令与网络,磁盘和日志监控总结
Linux系统命令与网络,磁盘和日志监控总结
67 0
|
2月前
|
监控 Linux 测试技术
Linux系统命令与网络,磁盘和日志监控三
Linux系统命令与网络,磁盘和日志监控三
45 0
下一篇
DataWorks