• aop实现记录后端用户访问


    记录:

      访问ip, 请求链接, 请求参数, 请求头, 返回信息...

    问题1:

      如何实现aop切片的就是Controller中的请求方法?

        监听xxxController下的所有方法?

          担心Controller中有部分方法是普通方法,例如private String datePares(Date date)这种

        使用过滤器?

          此业务不应该用过滤器

        使用拦截器?

          要求参照前面aop的例子完成,所以先不考虑。

      解决方案:

       spring的切点定义允许通过注解定位,结合execution表达式完成切点。

      @Pointcut(" @annotation(org.springframework.web.bind.annotation.PostMapping)"
          + " || @annotation(org.springframework.web.bind.annotation.PutMapping)"
          + " || @annotation(org.springframework.web.bind.annotation.DeleteMapping)"
          + " || @annotation(org.springframework.web.bind.annotation.RequestMapping)")
      private void requestAspect() {
      }
    
      @Pointcut("execution(* com.duoyu.home..* (..))")
      private void backendAspect() {
    
      }
    
      @Around("requestAspect() && backendAspect()")
      public Object run(ProceedingJoinPoint point) throws Throwable {

    问题2:

      处理方法中如何得到HttpServletRequest?

      spring提供了RequestContextListener这个监听器,针对请求,完成了一份数据的拷贝。(我使用的是boot,应该是直接自动配置了)

    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

     问题3:

      获得请求ip?请求方式?url?header头信息?请求参数?body体信息?

      获取请求ip前面想直接用request.getRemoteHost()获得,纠结remoteHost()和remoteAddr()有什么区别,于是上网找了个获取的方法,顺便简单针对被代理了的ip的追踪

    public static String getClientIp(HttpServletRequest request) {
        //反向代理了的话
        String ip = request.getHeader("x-forwarded-for");
        //多级反向代理处理
        if (ip != null && ip.contains(",")) {
          for (String ipItem : ip.split(",")) {
            if (!ipItem.equals("unknown")) {
              ip = ipItem;
              break;
            }
          }
        }
        //如果x-forwarded-for获取不到,或者是unknown,依旧使用了反向代理
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
          ip = request.getHeader("WL-Proxy-Client-IP");
        }
    
        //没有使用反向代理
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
          ip = request.getRemoteAddr();
        }
    
        return ip;
      }

      请求uri 和请求method很简单

      请求header:

        Map<String, String> headerMaps = new HashMap<String, String>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
          String key = (String) headerNames.nextElement();
          String value = request.getHeader(key);
          headerMaps.put(key, value);
        }
        String headers = JSONObject.toJSONString(headerMaps);
        visitRecordDo.setHeaders(headers);

      因为http请求的参数可能在body体内,也可能不在body体内,所以针对请求参数使用2种方式获得:

      1、  request.getParameterMaps() 然后遍历获取

      2、       request.getInputStream()读取流信息获取body数据

     

      响应信息,直接执行切点对象即可。

     Object resultObj = point.proceed();

    问题4:

      问题4是一个大问题,前面编写完毕后,简单使用看上去没问题。但是在我某些post操作时候后台日志报错:流已被关闭。

      为什么有的请求读取request的流不会被关闭有些被关闭呢?

        我发现出现流被关闭的都是使用了@RequestBody的注解的方法上。@RequestBody会读取request的body体内容且转化为对应对象。且断点发现@RequestBody注入的对象里面有值。

        也就是说,先进入的方法头,读取掉了request内容,然后再被aop切面,发现流关闭报错。

      怎么解决这个问题?

        拦截器是基于AOP实现的,好像只有过滤器能够优先执行。

        网上解决方案:

          过滤器拿到请求,读取请求信息存储到byte[]数组,然后返回一个包装的装载数组数据的request给下游。

          如:https://blog.csdn.net/a704397849/article/details/97267572

        我这里业务不应该使用过滤器,应该稍微变通了下我的需求,只要参数即可,那么我不区分其他参数和body体参数。使用切点的获取参数方法直接获取参数列表

        String params = JSONObject.toJSONString(point.getArgs());

  • 相关阅读:
    JS输入框正则校验
    JVM 参数查看与设置
    Java 设计模式汇总
    Android Notification
    Android PendingIntent
    Android AsyncTask详解
    Java Stake实现
    Camera2相机预览流程
    java annotation
    Java io包 FileInputStream&FileOutStream
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/13362639.html
Copyright © 2020-2023  润新知