逸帅 发表于 2021-2-4 18:02

springboot之aop切面获取请求中的信息

本帖最后由 逸帅 于 2021-2-4 18:10 编辑

springboot之aop切面获取请求
项目场景:

在学习springboot的博客开发中,通过aop切面,对博客中的操作进行记录

https://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.png


问题描述:
问题:
在切面方法中,无法获取请求的参数和类名,方法,ip等


https://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.png
解决方法:

@Before("log()")//调用log方法
    public void doBefore(JoinPoint joinPoint){
      System.out.println("------程序执行之前-----------");
      ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      HttpServletRequest request = requestAttributes.getRequest();
      String url = request.getRequestURL().toString();
      String ip= request.getRemoteAddr();
      Object[] args = joinPoint.getArgs();
//      类名-->方法名
      String methodName = joinPoint.getSignature().getDeclaringTypeName()+"-->"
                +joinPoint.getSignature().getName();
      getRequestLog getRequestLog = new getRequestLog(url,ip,methodName,args);
      System.out.println(getRequestLog);
    }





https://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.pnghttps://static.52pojie.cn/static/image/hrline/line7.png
过程:

RequestContextHolder是一个包含了request请求的容器,所以要获取请求中的信息,自然要从容器中获取。
然而RequestContextHolder只能获取RequestAttributes对象,要取得request,必须从ServletRequestAttributes获取
通过查看底层的源码,可以发现ServletRequestAttributes是继承了AbstractRequestAttributes,然后AbstractRequestAttributes继承了RequestAttributes
也就是说ServletRequestAttributes是RequestAttributes的子类,所以直接强转就可以了
通过强转后的ServletRequestAttributes直接getRequest,即可得到request对象

使用了内部类封装所需要打印的值

//    内部类,封装需要得到的值
    private class getRequestLog{
      private String url;
      private String ip;
      private String methodName;
      private Object[] requestParms;

    public getRequestLog() {
    }

    public getRequestLog(String url, String ip, String methodName, Object[] requestParms) {
      this.url = url;
      this.ip = ip;
      this.methodName = methodName;
      this.requestParms = requestParms;
    }

    @Override
    public String toString() {
      return "getRequestLog{" +
                "url='" + url + '\'' +
                ", ip='" + ip + '\'' +
                ", methodName='" + methodName + '\'' +
                ", requestParms=" + Arrays.toString(requestParms) +
                '}';
    }


hualonghongyan 发表于 2021-2-4 18:20

// 获取RequestAttributes
      RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
      // 从获取RequestAttributes中获取HttpServletRequest的信息
      HttpServletRequest request = (HttpServletRequest) requestAttributes
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);
// 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取切入点所在的方法
            Method method = signature.getMethod();
// 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            // 获取请求的方法名
            String methodName = method.getName();
            methodName = className + "." + methodName;
            // 请求的参数
            Map<String, String> rtnMap = converMap(request.getParameterMap());
            // 将参数所在的数组转换成json
            String params = JSONUtil.toJsonStr(rtnMap);

hualonghongyan 发表于 2021-2-4 18:21

看我上面的demo,你的那个 貌似不行

逸帅 发表于 2021-2-4 18:37

hualonghongyan 发表于 2021-2-4 18:21
看我上面的demo,你的那个 貌似不行

你这个demo应该是按照百度前面几篇文章得到的吧,我这个也能获取到值的,其实也差不多的,都是要得到ServletRequestAttributes对象,然后获得HttpServletRequest,requestAttributes可以直接调用getRequest方法哦,你可以试试,感觉比你那种简单一点点

Tisrop 发表于 2021-2-4 22:20

这种一般都是通过实现RequestBodyAdvice
@ControllerAdvice(assignableTypes={AnalyzeController.class})
public class RequestLogger implements RequestBodyAdvice, ResponseBodyAdvice<MyRequest> {
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
      return true;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
      return httpInputMessage;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParzameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
      MDC.put("key1","value1");
      MDC.put("key2","value2");
      MyRequestContextHolder.setContext(new MyRequest());
      RequestContextHolder.getRequestAttributes().setAttribute("",body, RequestAttributes.SCOPE_REQUEST);
      return body;
    }

    @Override
    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
      return o;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
      return true;
    }

    @Override
    public MyRequest beforeBodyWrite(MyRequest o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
      MDC.clear();
      MyRequestContextHolder.remove();
      return o;
    }
}

逸帅 发表于 2021-2-5 09:10

Tisrop 发表于 2021-2-4 22:20
这种一般都是通过实现RequestBodyAdvice
@ControllerAdvice(assignableTypes={Ana ...

应该是有多种方法,但是感觉RequestContextHolder好像看起来简单一点点{:301_978:}

hualonghongyan 发表于 2021-2-5 09:38

逸帅 发表于 2021-2-4 18:37
你这个demo应该是按照百度前面几篇文章得到的吧,我这个也能获取到值的,其实也差不多的,都是要得到Serv ...

好吧,我看差啦,我以为你贴的代码是获取不到的哈哈哈,原来是解决方案

逸帅 发表于 2021-2-5 11:53

hualonghongyan 发表于 2021-2-5 09:38
好吧,我看差啦,我以为你贴的代码是获取不到的哈哈哈,原来是解决方案

嘻嘻,没事啦,我们一起进步{:301_987:}
页: [1]
查看完整版本: springboot之aop切面获取请求中的信息