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

本文介绍了如何在SpringBoot项目中使用AOP(面向切面编程)来记录用户调用后端服务的详细操作日志,包括数据库表结构设计、实体类定义、Mapper接口、Service层接口以及AOP切面的实现,展示了如何通过注解记录操作类型、名称和描述等信息。
摘要由CSDN通过智能技术生成

业务分析

需求分析

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

技术实现分析

用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 Object 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);
        return result;
    }

}


知识点

AOP

  1. @Aspect: 用于定义一个切面,类似于 Java 中的类定义。
  2. @Pointcut: 用于定义一个切入点,表示在哪些连接点上应用切面的通知。
  3. @Before: 在目标方法执行前执行的通知。
  4. @After: 在目标方法执行后(无论正常返回还是异常返回)执行的通知。
  5. @AfterReturning: 在目标方法正常返回后执行的通知。
  6. @AfterThrowing: 在目标方法抛出异常后执行的通知。
  7. @Around: 环绕通知,包围目标方法执行。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值