基于OpenAPI(Swagger3)使用AOP技术,进行日志记录

1.Swagger3和AOP结合的好处

当我们使用接口,或者问题定位,我们需要知道这么几个比较常见的信息:

  1. 这个接口干嘛用的?
  2. 这个接口的请求地址,请求方式,请求参数,返回参数都是什么样?
  3. 这个接口的代码在哪里?
  4. 当这个接口出现问题时,当时的运行的参数是什么?

如果你的项目中用了Swagger,你大概也能看到如下这种在线的接口文档,我们可以看到接口模块的描述,具体接口的功能描述,接口地址,接口的请求参数,返回参数等。
在这里插入图片描述
那么我们在记录日志的时候,如果把上述的Swagger中的这些参数都能记录下来,那么对于我们的工作来说,不管是定位问题,还是做日志审计,都非常有帮助。
例如下述的日志所示,这样做有什么好处?

  1. 我们可以不修改/添加任何日志记录代码就能记录我们我们的接口(controller)的访问日志;
  2. 我们可以将接口的日志用统一的方式管理起来,方便做日志审计;
    在这里插入图片描述

2.Swagger需要做什么

OpenAPI(Swagger3)首先需要对两处地方进行标记,一个是标记Controller类,一个是标记Controller的方法,即

使用@Api(tags = "")来标注这个类干嘛用的,
使用@ApiOperation(value = "")来标注这个方法干嘛用的

在这里插入图片描述

3.AOP需要做什么

  1. 找到我们需要进行切入的点,即我们需要切入的点是在Swagger中被@ApiOperation所修饰的方法
 @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
  1. 增强@ApiOperation所修饰的方法,也就是记录@ApiOperation方法的访问日志
 logger.info("请求{}模块的[{}]服务start",获取@Api的描述说明,获取ApiOperation的描述说明);
 logger.info("请求地址:{}",获取请求地址);
 logger.info("请求方法:{}.{}",获取@Api修饰的类名, 获取ApiOperatio修饰的方法名);
 logger.info("请求参数:{}",获取请求参数);
 result = joinPoint.proceed();
 logger.info("请求{}模块的{}服务end",获取@Api的描述说明,获取ApiOperation的描述说明);
 //将日志进行持久化,比如保存到数据库,代码略

4.完整代码示例

import javax.servlet.http.HttpServletRequest;

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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.cloud.simulation.utils.JsonUtils;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * @description:基于swagger进行AOP日志记录
 * @author:hutao
 * @mail:hutao1@epri.sgcc.com.cn
 * @date:2022年10月17日 下午4:58:54
 */
@Aspect
@SpringBootConfiguration
public class LogApiConfig {
 
    private final Logger logger = LoggerFactory.getLogger(LogApiConfig.class);
	
    /**
     * @description:需要被切入的点是被@ApiOperation注解修饰的方法
     * @author:hutao
     * @mail:hutao1@epri.sgcc.com.cn
     * @date:2022年10月17日 下午4:59:20
     */
    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void pointcut() {
    	
    }
 
    /**
     * @description:进行日志切入
     * @author:hutao
     * @mail:hutao1@epri.sgcc.com.cn
     * @date:2022年10月17日 下午5:00:09
     */
    @Around("pointcut() && @annotation(apiOperation)")
    public Object around(ProceedingJoinPoint joinPoint, ApiOperation apiOperation) {
        Object result = null;
        try {
        	ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        	//获取请求地址
        	HttpServletRequest request = attributes.getRequest();
        	String url = request.getRequestURL().toString();
            //获取OpenAPI的类说明@Api
        	Class<?> controller = joinPoint.getThis().getClass();
            Api annotation = controller.getAnnotation(Api.class);
            String[] apiDes = annotation.tags();
            //获取被调用的方法名
            String methodName = joinPoint.getSignature().getName();
            //获取OpenAPI的方法说明@ApiOperation
			ApiOperation methodApiOperation = null;
			String apiOperationDes = "";
			MethodSignature ms = (MethodSignature) joinPoint.getSignature();
			methodApiOperation = ms.getMethod().getDeclaredAnnotation(ApiOperation.class);
			if (methodApiOperation != null) {
				apiOperationDes = methodApiOperation.value();
			}
            logger.info("请求{}模块的[{}]服务start",apiDes,apiOperationDes);
            logger.info("请求地址:{}",url);
            logger.info("请求方法:{}.{}", joinPoint.getSignature().getDeclaringTypeName(), methodName);
            logger.info("请求参数:{}",JsonUtils.javaBeanToString(joinPoint.getArgs()));//这里使用任意的Json转换工具即可
            result = joinPoint.proceed();
            logger.info("请求{}模块的{}服务end",apiDes,apiOperationDes);
        } catch (Throwable e) {
            logger.error("进行日志切入失败,失败原因:{}", e);
        }
        return result;
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值