Java语言Inputstream重复使用(输入流在第二次使用的时候会失效)

保存流对象(输入流在第二次使用的时候会失效),在需要用到InputStream的地方再将字节数组转化字节流使用,如果只需要用到一次inputstream流,就不用这样啦,直接用就OK。

下面直接上代码:

/**
 * 保存流对象(输入流在第二次使用的时候会失效)
 * 在需要用到InputStream的地方再封装成InputStream  
 * ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buf);  
 * Workbook wb = new HSSFWorkbook(byteArrayInputStream);//byteArrayInputStream 继承了InputStream,故这样用并没有问题
 * 如果只需要用到一次inputstream流,就不用这样啦,直接用就OK 
 * @param ins
 */
public byte[] saveaIns(InputStream ins){
	byte[] buf = null;
	try {
		if(ins!=null){
			buf = org.apache.commons.io.IOUtils.toByteArray(ins);//ins为InputStream流  
		}
	} catch (IOException e) {
		e.printStackTrace();
	}
	return buf;
}
<think>好的,我现在需要解决用户关于Spring HandlerInterceptor中第二次调用request.getParameter()返回null的问题。首先,我得理解用户的疑问,然后逐步分析可能的原因和解决方案。 用户提到在HandlerInterceptor中,第二次获取请求参数时得到null。这可能是因为请求的输入流只能被读取一次,之后流的位置已经到达末尾,再次读取时自然没有数据了。我需要回忆一下Servlet的Request对象的工作机制。 首先,确认一下request.getParameter()的工作原理。当调用request.getParameter()时,Servlet容器会解析请求体中的数据,并将参数存储在一个Map中。但如果请求体是输入流(比如POST请求中的表单数据),一旦输入流被读取过一次,后续的读取就会返回null,因为流不可重复读取。 接下来,考虑HandlerInterceptor中的情况。如果在拦截器的preHandle方法中调用了request.getParameter(),这可能已经触发了输入流的读取。如果在后续的处理中(比如Controller或其他拦截器)再次调用getParameter(),这时候可能会因为流已经关闭而导致无法读取数据,进而返回null。 然后,需要验证这个猜想。用户可能是在拦截器里多次调用getParameter(),或者在拦截器和Controller中都调用了这个方法。这时候第二次调用就会失败。此外,如果请求是PUT或POST,并且参数是通过请求体传递的,这种情况更容易出现。 接下来,思考解决方案。常见的办法是将请求体缓存起来,以便多次读取。可以使用HttpServletRequest的装饰器模式,将输入流的内容读取并保存到一个字节数组或字符串中,之后通过重写getInputStream()和getReader()方法,使得每次读取都从这个缓存中获取数据。这样,即使多次调用getParameter(),也能正确获取参数。 另外,需要注意Spring的某些组件(比如@RequestBody)可能会提前读取输入流,导致后续无法读取。这时候即使没有在拦截器中调用getParameter(),也可能出现同样的问题。这时候同样需要包装请求对象来缓存请求体。 还需要提醒用户,在实现缓存时,要确保线程安全,并且正确处理字符编码等问题。同时,应避免在拦截器中过早读取参数,除非确实需要,否则最好让参数在Controller中处理,或者在需要时使用包装后的请求对象。 最后,可能需要提供具体的代码示例,帮助用户理解如何实现请求的包装和缓存。例如,可以自定义一个ContentCachingRequestWrapper,并在拦截器中将原始请求替换为该包装器,确保后续的读取操作都是基于缓存的副本。 总结一下,问题的核心在于请求体的输入流只能读取一次,导致后续的getParameter()调用失效。解决方案是缓存请求体,使得可以多次读取。用户需要在自己的拦截器中对请求进行包装,并在后续处理中使用包装后的请求对象。</think>在Spring框架中,使用`HandlerInterceptor`时,若第二次调用`request.getParameter()`返回`null`,通常是因为**HTTP请求的输入流(`InputStream`)只能被读取一次**。以下是逐步分析及解决方案: --- ### **问题原因** 1. **Servlet请求体的单次读取特性** 当HTTP请求的`InputStream`被读取后(例如通过`request.getParameter()`或`request.getReader()`),流的位置会到达末尾。后续再尝试读取时,流中已无数据,导致返回`null`。 2. **触发流读取的常见场景** - 在`HandlerInterceptor`的`preHandle()`方法中调用了`request.getParameter()`。 - 在过滤器链(Filter)或其他拦截器中提前读取了请求体。 - 使用`@RequestBody`注解的参数处理(Spring会提前读取流)。 --- ### **解决方案** #### 1. **缓存请求体(推荐)** 通过包装`HttpServletRequest`,将请求体内容缓存到内存中,支持多次读取。 **实现步骤:** 1. **创建自定义的`HttpServletRequestWrapper`** ```java public class ContentCachingRequestWrapper extends HttpServletRequestWrapper { private final ByteArrayOutputStream cachedContent; public ContentCachingRequestWrapper(HttpServletRequest request) throws IOException { super(request); cachedContent = new ByteArrayOutputStream(); // 将原始请求体内容复制到缓存 IOUtils.copy(request.getInputStream(), cachedContent); } @Override public ServletInputStream getInputStream() { // 从缓存中返回新的输入流 return new CachedServletInputStream(cachedContent.toByteArray()); } @Override public BufferedReader getReader() { // 从缓存中返回新的Reader return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(cachedContent.toByteArray()))); } } ``` 2. **在拦截器中替换原始请求** ```java @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 包装原始请求 ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request); // 后续操作使用包装后的请求 String param = wrappedRequest.getParameter("key"); return true; } ``` 3. **确保后续处理使用包装后的请求** 在Controller或其他组件中,确保使用的是包装后的`request`对象。 --- #### 2. **避免在拦截器中读取参数** 如果不需要在拦截器中提前处理参数,尽量避免调用`request.getParameter()`,将参数处理逻辑移到Controller中。 --- #### 3. **检查请求方法类型** - **GET请求**:参数通过URL传递,`request.getParameter()`不会触发流读取,可多次调用。 - **POST/PUT请求**:参数在请求体中,必须通过缓存方案解决。 --- ### **代码示例** ```java public class CacheRequestBodyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 包装请求以缓存请求体 ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request); // 第一次读取参数(正常) String firstRead = wrappedRequest.getParameter("param"); // 第二次读取参数(正常,因为缓存) String secondRead = wrappedRequest.getParameter("param"); // 将包装后的请求传递给后续流程 request = wrappedRequest; return true; } } ``` --- ### **注意事项** 1. **性能影响** 缓存请求体会增加内存消耗,需权衡是否必要。 2. **文件上传请求** 若请求包含大文件,缓存可能导致内存溢出,需特殊处理。 通过上述方案,可解决`HandlerInterceptor`中多次调用`request.getParameter()`返回`null`的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地表最强菜鸡

你的鼓励将是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值