实现接口记录操作日志,每个月的数据统计到一张表中

主要实现:

        1 在接口上添加注解,记录访问日志,并存储到数据库中

1 定义元注解。ApiLog

package com.ec.safety.common.annotation;

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

/**
 * 日志记录
 */

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ApiLog {
    String module() default "";
}

2 编写切面代码

package com.ec.safety.query.handler;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.ec.safety.common.annotation.ApiLog;
import com.ec.safety.common.constant.CommonConstant;
import com.ec.safety.common.model.CurrentUser;
import com.ec.safety.common.utils.CurrentUserUtil;
import com.ec.safety.query.entity.SysLogs;
import com.ec.safety.query.mapper.SysLogsMapper;
import com.ec.safety.query.mapper.TableCommonMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Objects;

@Slf4j
@Component
@Aspect
public class SysOperateLogAspect {


    @Around("@annotation(com.ec.safety.common.annotation.ApiLog)")
    public Object around(ProceedingJoinPoint pjp) throws Exception{
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        // 异步执行操作数据
        CurrentUser currentUser = CurrentUserUtil.getCurrentUserCommon();
        return insertLog(pjp, currentUser, request.getRemoteAddr(), request.getMethod(), request.getRequestURI());
    }


    private Object insertLog(ProceedingJoinPoint pjp, CurrentUser currentUser, String ip, String method, String requestURI) {
        SysLogsMapper logsMapper = SpringUtil.getBean(SysLogsMapper.class);
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        ApiLog operation = methodSignature.getMethod().getAnnotation(ApiLog.class);

        // 参数
        Object[] args = pjp.getArgs();
        // 参数类型
        Class<?>[] parameterTypes = methodSignature.getParameterTypes();
        // 参数名称
        String[] parameterNames = methodSignature.getParameterNames();

        String requestParams = null;
        if (ArrayUtil.isNotEmpty(parameterNames)) {
            JSONObject paramJson = new JSONObject();
            for (int i = 0; i < parameterNames.length; i++) {
                Class<?> parameterType = parameterTypes[i];
                if (!parameterType.isAssignableFrom(HttpServletRequest.class) && !parameterType.isAssignableFrom(HttpServletResponse.class)) {
                    paramJson.put(parameterNames[i], args[i]);
                }
            }
            if (paramJson.size() > 0) {
                requestParams = JSONObject.toJSONString(paramJson);
            }
        }
        String operateState = "成功";
        String exceptionMessage = requestParams;
        try {
            return pjp.proceed();
        } catch (Throwable e) {
            operateState = "失败";
            exceptionMessage = e.getMessage();
            throw new RuntimeException(exceptionMessage);
        } finally {
            try {
                TableCommonMapper tableCommonMapper = SpringUtil.getBean(TableCommonMapper.class);
                String tableName = CommonConstant.SYS_LOGS_TABLE + LocalDateTimeUtil.format(LocalDate.now(), DatePattern.SIMPLE_MONTH_PATTERN);
                // 检查新表是否存在 如果不存在 则创建表
                Integer tableNum = tableCommonMapper.isExistTable("public", tableName);
                if (tableNum == 0) {
                    String newTable = CommonConstant.PUBLIC + "." + tableName;
                    logsMapper.copyTable(newTable, tableName + "_pkey");
                }
                SysLogs logs = new SysLogs();
                if (currentUser != null) {
                    logs.setUserId(currentUser.getId()).setUserName(currentUser.getUsername()).setMobile(currentUser.getMobilePhone());
                }
                logs.setIpAddress(ip)
                        .setModule(operation.module())
                        .setTitle(operation.module())
                        .setReqPath(method + ":" + requestURI)
                        .setOperateStatus(operateState).setRequestParam(requestParams)
                        .setContent(exceptionMessage)
                        .setCreateTime(LocalDateTime.now());
                logsMapper.insert(logs);
            } catch (Exception e) {
                log.error("保存操作日志失败:", e);
            }
        }
    }
}

3 检查数据库表是否存在,代码如下

 <select id="isExistTable" resultType="java.lang.Integer" parameterType="java.lang.String">
        SELECT
            COUNT(1)
        FROM information_schema.tables
        WHERE
            table_schema = #{tableSchema}
          AND table_name = #{tableName}
    </select>

4 如果不存在,创建表,代码如下:

<update id="copyTable" parameterType="java.lang.String">
        CREATE TABLE ${newTable} (
          id varchar(50) NOT NULL,
          user_id varchar(50) NULL,
          "module" varchar(100) NULL,
          title varchar(100) NULL,
          ip_address varchar(100) NULL,
          req_path varchar(100) NULL,
          operate_status varchar(10) NULL,
          "content" text NULL,
          user_name varchar(100) NULL,
          mobile varchar(20) NULL,
          request_param text NULL,
          create_time timestamp NULL,
          CONSTRAINT ${tablepKey} PRIMARY KEY (id)
        );
    </update>

5 在需要的接口上增加注解,功能实现

完成,是不是很简单呢,我们下次见

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天雨编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值