SpringBoot项目中基于AOP注解方式实现接口日志记录

前言

  • 最近要对系统进行改造,要对业务中的一些接口进行记录,包括接口调用时间,参数,操作类型,最后决定以注解的方式去实现,涵盖了AOP的基本用法及常用注解,不会对原来的业务逻辑产生影响,下面介绍一下具体的实现方式。

实现

  1. 首先创建一个注解
package com.dev.common.annotation;

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

/**
 * @Version 1.0
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLog {

    /**
     * 传入需要获取的参数,可在default设置默认值
     */
    String moduleName() default "内容管理";

    /**
     * 操作类型
     */
    String operateType();
}


  1. 定义一个切面类,加上@Component注解,@Aspect注解加入配置管理,可以通过Hutool提供的方法获取客户端浏览器,操作系统,ip地址,使用Hutool需要引入依赖
<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>5.8.0.M2</version>
</dependency>

package com.dev.common.service;

import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.dev.common.annotation.OperationLog;
import com.dev.common.utils.IpUtil;
import com.dev.common.utils.ParamsUtil;
import com.dev.service.CommonService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.NamedThreadLocal;
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.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 操作日志处理类
 * @Version 1.0
 */
@Aspect
@Component
@Slf4j
public class OperateLogAspect {

    @Resource
    private LogDao logDao;

    /** 计算操作消耗时间 */
    private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");

    /**
     * 处理请求前执行
     */
    @Before(value = "@annotation(operationLog)")
    public void boBefore(JoinPoint joinPoint, OperationLog operationLog)
    {
        TIME_THREADLOCAL.set(System.currentTimeMillis());
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     * @param operationLog 注解
     */
    @AfterReturning(pointcut = "@annotation(operationLog)")
    public void doAfterReturning(JoinPoint joinPoint, OperationLog operationLog)
    {
        handleLog(joinPoint,operationLog,null);
    }

    /**
     * 拦截异常操作,方法异常时执行
     *
     * @param joinPoint 切点
     * @param operationLog 注解
     * @param e 异常
     */
    @AfterThrowing(value = "@annotation(operationLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, OperationLog operationLog, Exception e)
    {
        handleLog(joinPoint, operationLog,e);
    }

    /**
     * 封装日志
     * @param joinPoint
     * @param operationLog
     * @param e
     */
    public void handleLog(final JoinPoint joinPoint,OperationLog operationLog,final Exception e) {

        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getRequest();
            //获取请求参数
            String reqParam = preHandleParams(joinPoint, request);
            String userIp = IpUtil.getIpAddrPlus(request);
            String uaStr = request.getHeader("User-Agent");
            UserAgent userAgent = UserAgentUtil.parse(uaStr);
            //计算耗时
            long cost = System.currentTimeMillis() - TIME_THREADLOCAL.get();
            Map<String,Object> operLogMap = new HashMap<>();
            operLogMap.put("clientIp",userIp);
            operLogMap.put("requestUrl",request.getRequestURI());
            operLogMap.put("requestParam",request.getParameterMap().toString());
            // 获取自定义注解的参数
            operLogMap.put("moduleName",operationLog.moduleName());
            operLogMap.put("requestDuration",cost);
            // 默认成功
            operLogMap.put("isSuccess",1);
            operLogMap.put("errorMessage","");
            // 失败回填0,错误原因
            if(e != null){
                operLogMap.put("isSuccess",0);
                operLogMap.put("errorMessage",e.getMessage());
            }
            // 插入日志
            logDao.insertLog(operLogMap);
        } catch (Exception exp) {
            exp.printStackTrace();
        } finally {
            TIME_THREADLOCAL.remove();
        }
    }


}


如果是springMVC项目还需在springMVC项目中需要开启AspectJ注解支持

<?xml encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:mvc="http://www.springframework.org/schema/mvc"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:p="http://www.springframework.org/schema/p"
	   xmlns:util="http://www.springframework.org/schema/util" 	
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/util/spring-util-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	
	<aop:aspectj-autoproxy/>

</beans>

  1. 在你的方法接口上加上自定义注解,传入一些参数,就可以使用了.
   @GetMapping("/hello")
    @OperationLog(moduleName = "文章管理",operateType = "插入")
    public Result Hello(HttpServletRequest request){
        HashMap<Object, Object> result = new HashMap<>();
        result.put("code",200);
        result.put("msg","success");
        return Result.success(result);
    }

   @GetMapping("/test")
    @OperationLog(moduleName = "测试管理",operateType = "更新")
    public Result Hello(HttpServletRequest request){
        HashMap<Object, Object> result = new HashMap<>();
        result.put("code",200);
        result.put("msg","success");
        return Result.success(result);
    }

原文链接:https://blog.csdn.net/Jnsone/article/details/129934551

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值