zoukankan      html  css  js  c++  java
  • springboot springmvc拦截器 拦截POST、PUT、DELETE请求参数和响应数据,并记录操作日志

    1.操作日志实体类

    @Document(collection = "operation_log")
    @Getter
    @Setter
    @ToString
    public class OperationLog extends BaseEntityWithId {
      private String userId; // 操作人
      private String resource; // 操作的资源
      private String requestMethod; // 请求方式
      private String beanName; // 操作的类
      private String methodName; // 操作的模块
      private String requestParams; // 请求的参数
      private String responseData; // 返回数据
    }

    2.拦截器

    package com.vian.admin.config;
    
    import com.alibaba.fastjson.JSON;
    import com.vian.admin.entity.OperationLog;
    import com.vian.admin.event.OperationLogEvent;
    import com.vian.core.configuration.event.EventPublisher;
    import com.vian.microservice.security.SecurityUtils;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    
    
    @Aspect
    @Component
    @Slf4j
    public class RequestLogAspect {
      @Autowired private EventPublisher eventPublisher;
      private ThreadLocal<OperationLog> logThreadLocal = new ThreadLocal<>();
      //拦截web下所有方法
      @Pointcut("execution(* com.vian.admin.web..*.*(..))")
      public void pointcut() {
        log.info("拦截请求start");
      }
    
      @Before("pointcut()")
      public void doBefore(JoinPoint joinPoint) {
    
        ServletRequestAttributes attributes =
            (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String beanName = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        String uri = request.getRequestURI();
        String userId = SecurityUtils.getCurrentUserId();
        //get方法不记录日志
        if ("GET".equals(request.getMethod())) {
          return;
        }
        //请求参数
        Object[] paramsArray = joinPoint.getArgs();
        log.info(
            "请求日志拦截:userId={}, uri={}, method={}, request={}",
            userId,
            uri,
            request.getMethod(),
            paramsArray);
        // 组装日志数据
        OperationLog optLog = new OperationLog();
        optLog.setUserId(userId);
        optLog.setResource(uri);
        optLog.setRequestMethod(request.getMethod());
        optLog.setBeanName(beanName);
        optLog.setMethodName(methodName);
        optLog.setRequestParams(argsArrayToString(paramsArray));
        logThreadLocal.set(optLog);
      }
    
      @AfterReturning(returning = "result", pointcut = "pointcut()")
      public void doAfterReturning(Object result) {
        try {
          // 处理完请求,从线程变量中获取日志数据,并记录到db
          OperationLog optLog = logThreadLocal.get();
          if (null != optLog) {
            optLog.setResponseData(JSON.toJSONString(result));
            eventPublisher.publish(new OperationLogEvent(this, optLog));
          }
        } catch (Exception e) {
          log.error("***操作请求日志记录失败doAfterReturning()***", e);
        } finally {
          // 清除threadlocal
          logThreadLocal.remove();
        }
      }
    
      /**
       * 请求参数拼装
       *
       * @param paramsArray
       * @return
       */
      private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
          for (int i = 0; i < paramsArray.length; i++) {
            Object jsonObj = JSON.toJSON(paramsArray[i]);
            params += jsonObj.toString() + " ";
          }
        }
        return params.trim();
      }
    }

    测试结果:

  • 相关阅读:
    Math类四个常用方法辨析,floor、ceil、round、rint
    【转】ctypes库的使用整理
    【转】采用dlopen、dlsym、dlclose加载动态链接库【总结】
    【转】collectd的部署
    【转】Pycharm Professional(专业版)完美破解,
    【转】在结构体最后定义一个长度为0的字符数组(技巧)
    【转】C++11智能指针之weak_ptr
    轻量级、高性能http代理服务器,内网穿透从未如此简单。
    php 大文件上传 redis+php resque 较低io消耗
    leetcode 870. 优势洗牌
  • 原文地址:https://www.cnblogs.com/yangzhenlong/p/9060659.html
Copyright © 2011-2022 走看看