最近准备在原有的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 { }
}

引用的类

 import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader; import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import jodd.JoddDefault;
import jodd.io.StreamUtil; public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)throws IOException {
super(request);
body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
} @Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() { @Override
public int read() throws IOException {
return bais.read();
}
};
}
}

关于springmvc时request的getReader()和getInputStream()只能调用一次的解决办法的更多相关文章

  1. ServletRequest中getReader()和getInputStream()只能调用一次的解决办法

    转载:http://blog.sina.com.cn/s/blog_870cd7b90101fg58.html 最近使用spring mvc做项目,数据格式是json,有一个功能是实现记录请求的参数, ...

  2. ServletRequest中getReader()和getInputStream()只能调用一次的解决办法(转)

    原文地址:http://liwx2000.iteye.com/blog/1542431 原文作者:liwx2000 为了提高项目安全性,拦截非法访问,要给项目增加了一个过滤器,拦截所有的请求,校验是否 ...

  3. 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.

    由于 request中getReader()和getInputStream()只能调用一次 在项目中,可能会出现需要针对接口参数进行校验等问题. 因此,针对这问题,给出一下解决方案 实现方法:先将Re ...

  4. Sqlserver2005附加数据库时出错提示操作系统错误5(拒绝访问)错误5120的解决办法

    Sqlserver2005附加数据库时出错提示操作系统错误5(拒绝访问)错误5120的解决办法 最近几天从网上找了几个asp.net的登录案例想要研究研究代码,结果在用 Sql Server2005附 ...

  5. 运行WampServer时,提示Exception Exception in module wampmanager.exe at 000F15A0.解决办法

    出现问题:运行WampServer时,提示Exception Exception in module wampmanager.exe at 000F15A0.解决办法 出现问题原因: ①:缺少Visu ...

  6. SQLServer2005+附加数据库时出错提示操作系统错误5(拒绝访问)错误5120的解决办法

    SQLServer2005+ 附加数据库时出错提示操作系统错误5(拒绝访问)错误5120的解决办法 我们在用Sql SQLServer2005+附加数据库文件时弹出错误信息如下图的处理办法: 方案一: ...

  7. [经使用有效]Sqlserver2005附加数据库时出错提示操作系统错误5(拒绝访问)错误5120的解决办法

    sqlserver2005附加数据库时出错提示操作系统错误5(拒绝访问)错误5120的解决办法 最近几天从网上找了几个asp.net的登录案例想要研究研究代码,结果在用 Sql Server2005附 ...

  8. Eclipse中利用JSP把mysql-connector-java-8.0.13.jar放到WebContent\WEB-INF\lib中连接MySQL数据库时Connection conn = DriverManager.getConnection(url,username,password)报错的解决办法

    开发环境: 1.系统:windows 7/8/10均可 2.jdk:1.8.0_144 3.服务器:apache-tomcat-9.0.8 4.IDE:eclipse+jsp 0.网页代码如下: &l ...

  9. Eclipse部署Maven web项目到tomcat服务器时,没有将lib下的jar复制过去的解决办法

    我们在做web开发是,经常都要在eclipse中搭建web服务器,并将开发中的web项目部署到web服务器进行调试,在此,我选择的是tomcat服务器.之前部署web项目到tomcat进行启动调试都很 ...

随机推荐

  1. char , unsigned char 和 signed char 区别

    ANSI C 提供了3种字符类型,分别是char.signed char.unsigned char.char相当于signed char或者unsigned char,但是这取决于编译器!这三种字符 ...

  2. listview展示倒计时

    public class MainActivity extends Activity { /**截至时间数据源**/ private List<Date> listData; /**当前时 ...

  3. mac双系统用磁盘工具合并windows分区后,开机还会 出现win分区

    如何删除开机硬盘的选择项 打开终端,输入sudo mount -t msdos /dev/disk0s1 /mnt 在Finer中会出现EFI盘,删除其中的Apple文件以外的文件即可(Apple千万 ...

  4. Ubuntu 重装 mysql

    我另篇blog有提到修改完my.cnf文件后mysql server重新启动失败,就是说mysql server启动不起来了,于是我就想到重装再试试,没想到就好了. 重装mysql之前需要卸载干净,删 ...

  5. 【模板】二分图最大权完美匹配KM算法

    hdu2255模板题 KM是什么意思,详见百度百科. 总之知道它可以求二分图最大权完美匹配就可以了,时间复杂度为O(n^3). 给张图. 二分图有了边权,求最大匹配下的最大权值. 所以该怎么做呢?对啊 ...

  6. JS和CSS中引号的使用

        font-family属性值如果是英文可以不加引号,如果是中文按照CSS标准则应该加引号,但不加引号也没关系.比如:font-family:Arial,"宋体"," ...

  7. R语言各种假设检验实例整理(常用)

    一.正态分布参数检验 例1. 某种原件的寿命X(以小时计)服从正态分布N(μ, σ)其中μ, σ2均未知.现测得16只元件的寿命如下: 159 280 101 212 224 379 179 264  ...

  8. 51单片机I/O口直接输入输出实例(附调试及分析过程)

    51单片机P0/P1/P2/P3口的区别: P0口要作为低8位地址总线和8位数据总线用,这种情况下P0口不能用作I/O,要先作为地址总线对外传送低8位的地址,然后作为数据总线对外交换数据: P1口只能 ...

  9. FreeSWITCH 安装配置的 各种坑, 填坑

    个人安装环境: OS:CentOS6.7 64位 FreeSWITCH Ver:1.6.17 一. 编译出错 安装 之前, 最好 先安装 这几个东西(如果有, 请忽略): yasm (有nasm的话 ...

  10. bootstrap快速入门笔记(七)-表格,表单

    一,表格 1,<table>中加.table类 2,条纹表格:通过 .table-striped 类可以给 <tbody> 之内的每一行增加斑马条纹样式. **跨浏览器兼容性: ...