调用接口信息入库的小工具(AOP切面实战)

1. 需求

  1. 每当有请求访问服务A的接口的时候,服务A会把调用的方法,入参,返回的结果等相关信息存储下来,入库。

2. 实现原理

  1. 使用AOP方式,在不改变原来方法的基础上,对原来方法进行增强,使用的是环绕通知
  2. 最终效果:自定义注解RequestLog,在方法上可以被使用,被该注解使用的方法,每次被调用的时候,就会记录调用的入参,返回值内容。
    AOP相关知识请看https://blog.csdn.net/xueyijin/article/details/121893953
  3. 代码:
    1. 先编写 记录请求日志的对象RequestLogEntity

      @Builder
      @Data
      public class RequestLogEntity {
      	//  请求来源
          private RequestSource source;
          // 请求入参
          private String request;
          // 请求返回结果
          private String response;
          // 请求的方法名
          private String apiName;
          // 调用方法的执行所需时间
          private Long duration;
          // 创建时间
          private Date techCreateTime;
      }
      
    2. 编写请求来源枚举

      public enum RequestSource {
          SELECT,
          UPDATE,
          DELETE,
          INSERT,
      }
      
    3. 创建对应的数据库表
      在这里插入图片描述

    4. 编写对应的dao层

      public interface RequestLogDao {
          void insert(RequestLogEntity requestLogEntity);
      }
      
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.jin.king.RecordRequestLogUtils.api.RequestLogDao">
          <insert id="insert" parameterType="requestLogEntity">
              insert into requestLog values (#{apiName},#{source},#{request},#{response},#{duration},#{techCreateTime})
          </insert>
      </mapper>
      
    5. 编写注解RequestLog

      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.METHOD})
      public @interface RequestLog {
          RequestSource source();
      }
      
    6. 编写切面Aspect代码(核心代码)

      @Component
      @Aspect
      @Slf4j
      @RequiredArgsConstructor
      public class RequestAspect {
      	// 使用构造函数注入
      	// lombok的注解RequiredArgsConstructor
      	// 要求 被构造的属性必须是 不可变类型
          private final RequestLogDao requestLogDao;
      
      	// 切点:被RequestLog注解注解的方法
          @Pointcut("@annotation(requestLog)")
          private void AspectRequestLog(RequestLog requestLog){
      
          }
      
          @Around("AspectRequestLog(requestLog)")
          public Object RecodeRequestLog(ProceedingJoinPoint joinPoint, RequestLog requestLog) throws Throwable{
              // 获取被增强的方法名字
              String apiName = joinPoint.getSignature().getName();
              // 获取被增强方法的参数
              Object[] args = joinPoint.getArgs();
              // 将请求的参数转化为 字符串
              String request = parseArgsToString(args);
              Object result;
              String response = null;
              Exception exception = null;
              long start = System.currentTimeMillis();
              try{
                  result = joinPoint.proceed(args);
              } catch (Exception e){
              	log.error("请求报错:{0}", e.getMessage());
                  result = e.getMessage();
                  exception = e;
              }
              //   将请求的返回参数转化为 字符串
              response = parseResultToString(result);
              long end = System.currentTimeMillis();
              RequestLogEntity requestLogEntity = RequestLogEntity.builder()
                      .apiName(apiName)
                      .request(request)
                      .response(response)
                      .duration((end - start) / 1000L)
                      .source(requestLog.source())
                      .techCreateTime(new Date())
                      .build();
              // requestLogEntity  将对象写入到数据库中 记录下来
              requestLogDao.insert(requestLogEntity);
      
              if(exception != null){
                  throw exception;
              }
              return result;
          }
      	// 转化为String
          private String parseArgsToString(Object[] args){
              return Arrays.stream(args).map(arg -> {
                  if(arg instanceof String){
                      return (String) arg;
                  }
                  return JSONObject.toJSONString(arg);
              }).collect(Collectors.joining(","));
          }
      
          private String parseResultToString(Object result){
              return JSONObject.toJSONString(result);
          }
      }
      

3. 测试

  1. 编写了一个测试案例

    @RestController
    @RequiredArgsConstructor
    public class UserController {
    
        private final UserService userService;
    
        @GetMapping("/select")
        // 加上RequestLog注解,调用这个方法的时候
        // 会先去调用 RequestAspect 方法
        @RequestLog(source = RequestSource.SELECT)
        public List<User> selectUser(){
            return userService.selectUser();
        }
    
        @PostMapping("/insert")
        @RequestLog(source = RequestSource.INSERT)
        public void insertUser(@RequestBody User user){
            userService.insertUser(user);
        }
    }
    
    @Service
    @RequiredArgsConstructor
    public class UserService {
    
        private final UserDao userDao;
    
        public List<User> selectUser() {
            return userDao.selectUser();
        }
    
        public void insertUser(User user) {
            userDao.insertUser(user);
        }
    }
    
    
    public interface UserDao {
        List<User> selectUser();
    
        void insertUser(User user);
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.jin.king.RecordRequestLogUtils.dao.UserDao">
        <select id="selectUser" resultType="com.jin.king.RecordRequestLogUtils.domain.User">
            select * from user;
        </select>
    
        <insert id="insertUser" parameterType="com.jin.king.RecordRequestLogUtils.domain.User">
            insert into user values (#{username},#{password},#{hobby})
        </insert>
    </mapper>
    
  2. 测试:
    初始表 :分别是RequestLog表,以及User表在这里插入图片描述
    在这里插入图片描述
    调用select接口:
    在这里插入图片描述在这里插入图片描述
    调用insert接口:

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值