当前位置: 首页 > news >正文

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

文章目录

    • 1.Swagger3和AOP结合的好处
    • 2.Swagger需要做什么
    • 3.AOP需要做什么
    • 4.完整代码示例

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;
    }
}

相关文章:

  • 碎碎念,有关果园就业生涯应该如何规划
  • 4G组网三相四线预付费电表-远程集中抄表
  • 李沐66_使用注意力机制的seq2seq——自学笔记
  • 20232937文兆宇 2023-2024-2 《网络攻防实践》实践七报告
  • POJO,Entity,model,domain,view,DTO,VO,Param这些分别都是什么含义?怎样理解?
  • Java23种设计模式-创建型模式之建造者模式
  • 【微信小程序】实现授权登入---超详细讲解
  • 183896-00-6,Biotin-C3-PEG3-C3-NH2,可以选择性降解靶蛋白
  • 高校宣讲会管理系统|基于Springboot的高校宣讲会管理系统设计与实现(源码+数据库+文档)
  • 后端实现跨域(三种方式)
  • 【坑】Spring Boot整合MyBatis,一级缓存失效
  • 深度学习中数据的转换
  • JAVAEE框架数据库技术之13_oracle 之PLSQL技术及存储过程和函数
  • 【PyTorch深度学习项目实战100例】—— 基于UNet实现血管瘤超声图像分割 | 第30例
  • 浅谈面向对象设计思想,以及在Linux内核中的体现
  • Mybatis——进阶
  • 简单上手_Kotlin,让开发更简洁
  • 机器学习——代价函数
  • 【百日刷题计划 第八天】——熟悉字符串 字符串基础题
  • python 处理阻尼正弦
  • 人工智能基础:人工智能云服务(Alaas)介绍
  • 【Leetcode】1092. Shortest Common Supersequence
  • Datawhale 202210 Excel | 第五、六、七章 Excel函数示例 Excel函数列表
  • matlab实时串口通讯示例
  • 18-CSS3的2D和3D属性
  • 【韩顺平老师讲MySQL】数据类型详解
  • 认识和了解Linux文件系统。
  • Simulink 自动代码生成电机控制:基于Keil软件集成
  • 【ArchSummit】小红书缓存服务多云建设之路
  • Educational Codeforces Round 137 (Rated for Div. 2)-赛后总结
  • Python图形处理
  • 【网站架构】4核CPU的MySQL调优3万RPS吞吐量?数据库集群高可用