zoukankan      html  css  js  c++  java
  • 关于springmvc时request的getReader()和getInputStream()只能调用一次的解决办法

      最近准备在原有的SSM项目的基础上添加完善的日志分析,由于是APP的后台系统,之前在规划APP的时候,并没有在APP上做埋点的处理,而如果想要进行埋点处理的话,对于未能新升级的APP用户来说,就是去了意义,因为只要用户不升级,埋点就不能在他的APP中运行。所以,就考虑到了在后台的入口增加日志的监控。

      想法总是简单,但是在实际实现的过程中却还是遇到了问题。由于APP基本都采用公参的加密校验,然后采用POST请求传递JSON数据。对于一般的请求分析,比如每个时间段的访问量,或者每个方法每个某块的统计都简单,只要在拦截器中新增一个将数据扔到消息队列中,然后在消费端在进行日志的分析和处理即可。然后如果要针对每个用户在什么时间段,做了什么处理,问题就来了,因为这个时候就必须拿到post中的json参数。

      有些同学就说,这不是很简单么,直接request.getParameter()不就可以了吗?NO,post的json数据是通过流的方式传递的,并不可以直接读取。OK,那我们用request.getReader()拿到流然后转成字符串不就可以了么?那么问题来了,流是只能流一遍的,一旦读过了就不会再有了,具体的方法中就拿不到了。说到这里,其实访问根本就不会再进到方法体了,因为springmvc的DispatcherServlet就会抛出异常  getReader() has already been called for。。。。。。

      说了这么多,下面是重点啦,其实很简单,就是在过滤器处理request(如果没有过滤器,那就新增一个即可)

      实现方法:先将RequestBody保存为一个byte数组,然后通过Servlet自带的HttpServletRequestWrapper类覆盖getReader()和getInputStream()方法,使流从保存的byte数组读取。然后再Filter中将ServletRequest替换为ServletRequestWrapper。代码如下:

    BodyReaderHttpServletRequestWrapper类包装ServletRequest,将流保存为byte[],然后将getReader()和getInputStream()方法的流的读取指向byte[]

    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    
    public class AuthFilter implements Filter{
        
        public void destroy() {
            
        }
    
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            ServletRequest requestWrapper = null;  
            if(request instanceof HttpServletRequest) {  
                requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);  
            }
            if(null == requestWrapper) {  
                chain.doFilter(request, response);  
            } else {  
                chain.doFilter(requestWrapper, response);  
            }
        }
        
        /**
         * 初始化函数时,需要获取排除在外的url
         */
        public void init(FilterConfig config) throws ServletException {
        
        }
    }

    引用的类

     1 import java.io.BufferedReader;
     2 import java.io.ByteArrayInputStream;
     3 import java.io.IOException;
     4 import java.io.InputStreamReader;
     5 
     6 import javax.servlet.ServletInputStream;
     7 import javax.servlet.http.HttpServletRequest;
     8 import javax.servlet.http.HttpServletRequestWrapper;
     9 
    10 import jodd.JoddDefault;
    11 import jodd.io.StreamUtil;
    12 
    13 public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
    14     
    15     private final byte[] body;  
    16     
    17     public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)throws IOException {  
    18         super(request);  
    19         body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);  
    20     }  
    21   
    22     @Override  
    23     public BufferedReader getReader() throws IOException {  
    24         return new BufferedReader(new InputStreamReader(getInputStream()));  
    25     }  
    26   
    27     @Override  
    28     public ServletInputStream getInputStream() throws IOException {  
    29         final ByteArrayInputStream bais = new ByteArrayInputStream(body);  
    30         return new ServletInputStream() {  
    31   
    32             @Override  
    33             public int read() throws IOException {  
    34                 return bais.read();  
    35             }  
    36         };  
    37     }  
    38 }
  • 相关阅读:
    MySQL练习
    [转]mysql和redis的区别
    python框架面试题联系
    国内外免费接收短信验证码
    ubuntu环境下docker的安装与操作
    Django商城项目笔记No.18商品部分-数据表创建
    Django商城项目笔记No.17用户部分-用户中心用户地址管理
    Django商城项目笔记No.16用户部分-用户中心收货地址
    Django商城项目笔记No.15用户部分-用户中心邮箱验证
    Django商城项目笔记No.14用户部分-用户中心邮箱绑定
  • 原文地址:https://www.cnblogs.com/ocean-sky/p/6899613.html
Copyright © 2011-2022 走看看