转载:http://blog.sina.com.cn/s/blog_870cd7b90101fg58.html

最近使用spring mvc做项目,数据格式是json,有一个功能是实现记录请求的参数,而请求的参数是整个RequestBody,Controller里是用过@RequestBody获取的。实现方法是通过一个Filter读取整个RequestBody并记录。但是这时就遇到一个问题,ServletRequest的getReader()和getInputStream()两个方法只能被调用一次,而且不能两个都调用。那么如果Filter中调用了一次,在Controller里面就不能再调用了。查看了下ServletRequest的说明,如下:

Java代码
  1. public ServletInputStream getInputStream() throws IOException;
  2. public BufferedReader getReader() throws IOException;

两个方法都注明方法只能被调用一次,由于RequestBody是流的形式读取,那么流读了一次就没有了,所以只能被调用一次。既然是因为流只能读一次的原因,那么只要将流的内容保存下来,就可以实现反复读取了。

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

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

Java代码
  1. import java.io.BufferedReader;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import javax.servlet.ServletInputStream;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletRequestWrapper;
  8. import jodd.JoddDefault;
  9. import jodd.io.StreamUtil;
  10. public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
  11. private final byte[] body;
  12. public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
  13. throws IOException {
  14. super(request);
  15. body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);
  16. }
  17. @Override
  18. public BufferedReader getReader() throws IOException {
  19. return new BufferedReader(new InputStreamReader(getInputStream()));
  20. }
  21. @Override
  22. public ServletInputStream getInputStream() throws IOException {
  23. final ByteArrayInputStream bais = new ByteArrayInputStream(body);
  24. return new ServletInputStream() {
  25. @Override
  26. public int read() throws IOException {
  27. return bais.read();
  28. }
  29. };
  30. }
  31. }

在Filter中将ServletRequest替换为ServletRequestWrapper

Java代码
    1. public class HttpServletRequestReplacedFilter implements Filter {
    2. @Override
    3. public void init(FilterConfig filterConfig) throws ServletException {
    4. //Do nothing
    5. }
    6. @Override
    7. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
    8. ServletRequest requestWrapper = null;
    9. if(request instanceof HttpServletRequest) {
    10. requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
    11. }
    12. if(null == requestWrapper) {
    13. chain.doFilter(request, response);
    14. } else {
    15. chain.doFilter(requestWrapper, response);
    16. }
    17. }
    18. @Override
    19. public void destroy() {
    20. //Do nothing
    21. }
    22. }

ServletRequest中getReader()和getInputStream()只能调用一次的解决办法的更多相关文章

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

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

  2. 关于springmvc时request的getReader()和getInputStream()只能调用一次的解决办法

    最近准备在原有的SSM项目的基础上添加完善的日志分析,由于是APP的后台系统,之前在规划APP的时候,并没有在APP上做埋点的处理,而如果想要进行埋点处理的话,对于未能新升级的APP用户来说,就是去了 ...

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

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

  4. es6 Object.assign ECMAScript 6 笔记(六) ECMAScript 6 笔记(一) react入门——慕课网笔记 jquery中动态新增的元素节点无法触发事件解决办法 响应式图像 弹窗细节 微信浏览器——返回操作 Float 的那些事 Flex布局 HTML5 data-* 自定义属性 参数传递的四种形式

    es6 Object.assign   目录 一.基本用法 二.用途 1. 为对象添加属性 2. 为对象添加方法 3. 克隆对象 4. 合并多个对象 5. 为属性指定默认值 三.浏览器支持 ES6 O ...

  5. c++调用动态库失败解决办法

    c++调用动态库失败解决办法 之前写好的程序今天早上过来发现在服务器上出错了,于是就各种查问题,整整一个早上外加下午两个小时都在查这个问题,最终被我找到了问题: 在程序中我发现LoadLibrary( ...

  6. Android中View类OnClickListener和DialogInterface类OnClickListener冲突解决办法

    Android中View类OnClickListener和DialogInterface类OnClickListener冲突解决办法 如下面所示,同时导入这两个,会提示其中一个与另一个产生冲突. 1i ...

  7. .NET在IE9中页面间URL传递中文变成乱码的解决办法

     在.Net的项目中,鼠标点击查询按钮,转到查询页面,但URL中包含中文时,传到服务器端后,中文变成了乱码(只有IE9出现该问题).       尝试使用Server.UrlEncode()进行编码, ...

  8. Visual studio 2017中 Javascript对于Xrm对象模型没有智能提示的解决办法

    Visual studio 2017中 Javascript对于Xrm对象模型没有智能提示的解决办法 先上个图.语法提示支持到 Microsoft Dynamics xRM API 8.2 也就是cr ...

  9. electron-vue中使用iview 报错this. is readonly的解决办法

    title: electron-vue中使用iview 报错this. is readonly的解决办法 toc: false date: 2019-02-12 19:33:28 categories ...

随机推荐

  1. Markdown 使用说明

    使用说明 ========= @[手册|帮助|Markdown] - **马克飞象**是一款专为印象笔记打造的Markdown编辑器. - 特别需要说明的一点是增加了`@(笔记本)[标签]`语法,以此 ...

  2. margin的BUG

    在进行简单的div盒子嵌套时,发现设置margin-top时存在bug,然后就去谷歌搜索了一下,发现margin确实存在bug. bug的现象是父子元素嵌套时,如果子元素是块元素时,对块元素设置mar ...

  3. php读取excel日期类型数据的例子

    提供一个读取的函数:  代码如下 复制代码 //excel日期转换函数function excelTime($date, $time = false) { if(function_exists('Gr ...

  4. Maven入门指南⑤:使用Nexus搭建Maven私服

    1 . 私服简介 私服是架设在局域网的一种特殊的远程仓库,目的是代理远程仓库及部署第三方构件.有了私服之后,当 Maven 需要下载构件时,直接请求私服,私服上存在则下载到本地仓库:否则,私服请求外部 ...

  5. Windows Phone中的图形渲染处理

    前言    这篇文章主要介绍Windows Phone中XAML的渲染处理过程,你可以根据下文中所提到的内容来优化现有的XAML页面,来提高页面渲染的性能. XAML的渲染包括以下两个阶段: 1. 光 ...

  6. 解决sublime text 2总是在新窗口中打开文件

    在mac下不是很喜欢sublime text 2 总是在新窗口中打开文件,很麻烦,文件打多了,就会出现N多窗口,虽然可以直接打开当前目录可以解决,但有时候查看其它项目中的单个文件,就比较麻烦.百度一直 ...

  7. [原]项目进阶 之 持续构建环境搭建(二)Nexus私服器

    上一篇博文项目进阶 之 持续构建环境搭建(一)架构中,我们大致讲解了一下本系列所搭建环境的基本框架,这次开始我们进入真正的环境搭建实战.重点不在于搭建的环境是否成功和完善,而是在搭建过程中充分认识到每 ...

  8. C++中的运算符优先级

    1   ()  []  .  ->2   !  ~   -(负号) ++  --   &(取变量地址)*   (type)(强制类型)    sizeof 3   * / % 4   + ...

  9. 20145120 《Java程序设计》第2周学习总结

    20145120 <Java程序设计>第2周学习总结 教材学习内容总结 因为前面有学习过C语言以及汇编语言,类型.运算符.流程控制等很多都是之前接触过的,因此在学习第三章的时候感觉并非十分 ...

  10. Careercup - Google面试题 - 4807591515389952

    2014-05-06 00:45 题目链接 原题: What would happen if you have only one server for a web cache (a web brows ...