自定义记录日志的注解

自定义记录日志的注解

建日志表

sql 复制代码
CREATE TABLE `system_log` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `method_name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '方法名称',
  `url` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '路径',
  `request_params` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '请求参数',
  `response_result` text COLLATE utf8mb4_general_ci NOT NULL COMMENT '响应结果',
  `cost_time` int NOT NULL COMMENT '执行时间(毫秒)',
  `message` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '说明',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

实现代码

定义注解

java 复制代码
package com.study.systemlog;

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLogAOP {

}

与表对应的实体类

java 复制代码
package com.study.systemlog;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;

@Data
@TableName("system_log")
public class SystemLog {

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    private String methodName;

    private String url;

    private String requestParams;

    private String responseResult;

    private Long costTime;

    private String message;

    private Date createTime;

}

这里我用的是mybatisplus,如果这里的类名不是表名的驼峰命名,就需要加上 @TableName("system_log") 这个注解。

比如类名是 SystemLogDB,那么mybatisplus就会把这个类映射到表 system_log_d_b,而不是system_log

@TableId(value = "id", type = IdType.AUTO) 这个注解指定了ID字段是自增的。若没有这个注解,虽然传入的对象id值为null,但mybatisplus会自动给id分配一个随机值,然后写入数据库。这样就不能依靠数据库实现ID自增。

Mapper 和 Service

java 复制代码
package com.study.systemlog;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SystemLogMapper extends BaseMapper<SystemLog> {}
java 复制代码
package com.study.systemlog;

public interface SystemLogService {

    int insertSystemLog(SystemLog systemLog);

}
java 复制代码
package com.study.systemlog;

import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;

@Service
public class SystemLogServiceImpl implements SystemLogService {

    @Resource
    private SystemLogMapper systemLogMapper;

    @Override
    public int insertSystemLog(SystemLog systemLog) {
        systemLog.setCreateTime(new Date());
        return systemLogMapper.insert(systemLog);
    }

}

实现自定义注解

java 复制代码
package com.study.systemlog;

import com.alibaba.fastjson2.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Aspect
@Service("systemLogAOPService")
public class SystemLogAOPService {

    @Resource
    private SystemLogService systemLogService;

    @Pointcut("@annotation(com.study.systemlog.SystemLogAOP)")
    public void LogPointCut() {}

    @Around("LogPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        SystemLog systemLog = new SystemLog();

        // 请求路径
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        systemLog.setUrl(request.getRequestURI());

        long start = System.currentTimeMillis();

        // 拦截的方法名称。当前正在执行的方法
        String className = point.getTarget().getClass().getName();
        String methodName = point.getSignature().getName();
        systemLog.setMethodName(className + "." + methodName);

        // 拦截的放参数类型
        MethodSignature msig = (MethodSignature)point.getSignature();

        // 拦截的参数
        String[] parameterNames = msig.getParameterNames();
        Object[] args = point.getArgs();
        Map<String, Object> params = generateParams(parameterNames, args);
        systemLog.setRequestParams(JSON.toJSONString(params));

        try {
            // 获得被拦截的方法
            point.getTarget().getClass().getMethod(methodName, msig.getMethod().getParameterTypes());
        } catch (NoSuchMethodException | SecurityException e1) {
            log.error("获取方法异常:" + e1.getMessage());
        }

        // 执行方法返回对象
        Object object = point.proceed();
        try {
            systemLog.setResponseResult(JSON.toJSONString(object));
            systemLog.setCostTime(System.currentTimeMillis() - start);
            systemLog.setMessage("执行成功!");
        } catch (Throwable e) {
            systemLog.setCostTime(System.currentTimeMillis() - start);
            systemLog.setMessage("执行失败!" + e.getMessage());
            log.error("执行方法[" + methodName + "]异常!" + e.getMessage());
        }
        systemLogService.insertSystemLog(systemLog);
        return object;
    }

    private Map<String,Object> generateParams(String[] paramNames, Object[] values){
        Map<String,Object> rs = new HashMap<>();
        for (int i = 0; i < paramNames.length; i++) {
            rs.put(paramNames[i],values[i]);
        }
        return rs;
    }

}

需要导入的依赖

java 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>${spring-boot.version}</version>
</dependency>

为了方便,所有类都在同一层目录,也就是同一个包。

使用注解

将注解标在需要记录日志的方法上,就能实现日志功能。

java 复制代码
@SystemLogAOP
@GetMapping("/{id}")
public AjaxResult get(@PathVariable Long id) {
    return studentService.selectStudentById(id);
}

实现效果

相关推荐
兩尛2 分钟前
Spring面试
java·spring·面试
Java中文社群9 分钟前
服务器被攻击!原因竟然是他?真没想到...
java·后端
Full Stack Developme20 分钟前
java.nio 包详解
java·python·nio
零千叶36 分钟前
【面试】Java JVM 调优面试手册
java·开发语言·jvm
代码充电宝1 小时前
LeetCode 算法题【简单】290. 单词规律
java·算法·leetcode·职场和发展·哈希表
li3714908901 小时前
nginx报400bad request 请求头过大异常处理
java·运维·nginx
摇滚侠1 小时前
Spring Boot 项目, idea 控制台日志设置彩色
java·spring boot·intellij-idea
Aevget2 小时前
「Java EE开发指南」用MyEclipse开发的EJB开发工具(二)
java·ide·java-ee·eclipse·myeclipse
黄昏晓x2 小时前
C++----多态
java·jvm·c++
Brookty2 小时前
【算法】前缀和
java·学习·算法·前缀和·动态规划