ServletRequest中getReader()和getInputStream()只能调用一次的解决办法
转载:http://blog.sina.com.cn/s/blog_870cd7b90101fg58.html
最近使用spring mvc做项目,数据格式是json,有一个功能是实现记录请求的参数,而请求的参数是整个RequestBody,Controller里是用过@RequestBody获取的。实现方法是通过一个Filter读取整个RequestBody并记录。但是这时就遇到一个问题,ServletRequest的getReader()和getInputStream()两个方法只能被调用一次,而且不能两个都调用。那么如果Filter中调用了一次,在Controller里面就不能再调用了。查看了下ServletRequest的说明,如下:
- public ServletInputStream getInputStream() throws IOException;
- public BufferedReader getReader() throws IOException;
两个方法都注明方法只能被调用一次,由于RequestBody是流的形式读取,那么流读了一次就没有了,所以只能被调用一次。既然是因为流只能读一次的原因,那么只要将流的内容保存下来,就可以实现反复读取了。
实现方法:先将RequestBody保存为一个byte数组,然后通过Servlet自带的HttpServletRequestWrapper类覆盖getReader()和getInputStream()方法,使流从保存的byte数组读取。然后再Filter中将ServletRequest替换为ServletRequestWrapper。代码如下:
BodyReaderHttpServletRequestWrapper类包装ServletRequest,将流保存为byte[],然后将getReader()和getInputStream()方法的流的读取指向byte[]
- 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();
- }
- };
- }
- }
在Filter中将ServletRequest替换为ServletRequestWrapper
- public class HttpServletRequestReplacedFilter implements Filter {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- //Do nothing
- }
- @Override
- 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);
- }
- }
- @Override
- public void destroy() {
- //Do nothing
- }
- }
ServletRequest中getReader()和getInputStream()只能调用一次的解决办法的更多相关文章
- ServletRequest中getReader()和getInputStream()只能调用一次的解决办法(转)
原文地址:http://liwx2000.iteye.com/blog/1542431 原文作者:liwx2000 为了提高项目安全性,拦截非法访问,要给项目增加了一个过滤器,拦截所有的请求,校验是否 ...
- 关于springmvc时request的getReader()和getInputStream()只能调用一次的解决办法
最近准备在原有的SSM项目的基础上添加完善的日志分析,由于是APP的后台系统,之前在规划APP的时候,并没有在APP上做埋点的处理,而如果想要进行埋点处理的话,对于未能新升级的APP用户来说,就是去了 ...
- 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.
由于 request中getReader()和getInputStream()只能调用一次 在项目中,可能会出现需要针对接口参数进行校验等问题. 因此,针对这问题,给出一下解决方案 实现方法:先将Re ...
- es6 Object.assign ECMAScript 6 笔记(六) ECMAScript 6 笔记(一) react入门——慕课网笔记 jquery中动态新增的元素节点无法触发事件解决办法 响应式图像 弹窗细节 微信浏览器——返回操作 Float 的那些事 Flex布局 HTML5 data-* 自定义属性 参数传递的四种形式
es6 Object.assign 目录 一.基本用法 二.用途 1. 为对象添加属性 2. 为对象添加方法 3. 克隆对象 4. 合并多个对象 5. 为属性指定默认值 三.浏览器支持 ES6 O ...
- c++调用动态库失败解决办法
c++调用动态库失败解决办法 之前写好的程序今天早上过来发现在服务器上出错了,于是就各种查问题,整整一个早上外加下午两个小时都在查这个问题,最终被我找到了问题: 在程序中我发现LoadLibrary( ...
- Android中View类OnClickListener和DialogInterface类OnClickListener冲突解决办法
Android中View类OnClickListener和DialogInterface类OnClickListener冲突解决办法 如下面所示,同时导入这两个,会提示其中一个与另一个产生冲突. 1i ...
- .NET在IE9中页面间URL传递中文变成乱码的解决办法
在.Net的项目中,鼠标点击查询按钮,转到查询页面,但URL中包含中文时,传到服务器端后,中文变成了乱码(只有IE9出现该问题). 尝试使用Server.UrlEncode()进行编码, ...
- Visual studio 2017中 Javascript对于Xrm对象模型没有智能提示的解决办法
Visual studio 2017中 Javascript对于Xrm对象模型没有智能提示的解决办法 先上个图.语法提示支持到 Microsoft Dynamics xRM API 8.2 也就是cr ...
- electron-vue中使用iview 报错this. is readonly的解决办法
title: electron-vue中使用iview 报错this. is readonly的解决办法 toc: false date: 2019-02-12 19:33:28 categories ...
随机推荐
- Cookie与Session详解
来源:<PHP核心技术与最佳实践> 列旭松 陈文 著 Cookie与Session详解读书笔记,从概念.操作.应用.注意事项以及区别等几方面详细阐述两者的基础知识,它们都是针对HTTP协议 ...
- 【Qt】Qt之进程间通信(IPC)【转】
简述 进程间通信,就是在不同进程之间传播或交换信息.那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区.但是,系统空间却是“ ...
- 免费GIT托管
http://www.gitcentral.com http://www.projectlocker.com http://gitfarm.appspot.com http://code.google ...
- [大牛翻译系列]Hadoop(8)MapReduce 性能调优:性能测量(Measuring)
6.1 测量MapReduce和环境的性能指标 性能调优的基础系统的性能指标和实验数据.依据这些指标和数据,才能找到系统的性能瓶颈.性能指标和实验数据要通过一系列的工具和过程才能得到. 这部分里,将介 ...
- Codeforces 559A 第六周 O题
Description Gerald got a very curious hexagon for his birthday. The boy found out that all the angle ...
- MyEclipse反编译Class文件
对于需要查看Java Class文件源码的筒子们来说,必须在项目中导入Java源码才能查看Class文件的具体实现,这不仅十分的麻烦,因为有时我们并不可以获得Class文件对应的Java源码.今天就给 ...
- 基于UUID生成短ID
为什么需要短ID 数据库操作过程最常用到: 自增ID UUID 前者多数依赖Mysql的auto_increment,但数据移植麻烦. 如果是主从或主主,不同库里自增ID还可能不一致. 后者长度是个问 ...
- json的序列化和反序列化支持时间格式转换
.NET自带的json序列有时间格式问题,为了解决自己写了个json格式的序列化和反序列化 1.引入的命名空间 using System; using System.Collections.Gener ...
- AVPlayer的基本使用
2014-5-7 06:46| 发布者: admin| 查看: 437| 评论: 0 摘要: 在iOS开发中,播放视频通常有两种方式,一种是使用MPMoviePlayerController(需要 ...
- iTween基础之Rotate(旋转角度)
一.基础介绍:二.基础属性 原文地址 :http://blog.csdn.net/dingkun520wy/article/details/50696489 一.基础介绍 RotateTo:旋转游戏物 ...