SpringBoot项目中使用request.getInputStream()获取参数时出现java.io.IOException: Stream closed

简介: @RequestBody注解会先调用request.getInputStream()这个方法获取参数,然而request.getInputStream()这个流只能被读取一次,所以我们再次读取这个流就会报错。解决方案: 最简单的方案就是 先读取流,然后在将流写进去就行了


原因:@RequestBody注解会先调用request.getInputStream()这个方法获取参数,然而request.getInputStream()这个流只能被读取一次,所以我们再次读取这个流就会报错。
解决方案: 最简单的方案就是 先读取流,然后在将流写进去就行了

新建HttpHelper (用于读取Body)
package com.xxx.util.core.filter.request;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class HttpHelper {

public static String getBodyString(HttpServletRequest request) throws IOException {
    StringBuilder sb = new StringBuilder();
    InputStream inputStream = null;
    BufferedReader reader = null;
    try {
        inputStream = request.getInputStream();
        reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
        String line = "";
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return sb.toString();
}

}

新建RequestReaderHttpServletRequestWrapper(防止流丢失)
package com.xxx.util.core.filter.request;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class RequestReaderHttpServletRequestWrapper extends HttpServletRequestWrapper{

private final byte[] body;

public RequestReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
    super(request);
    body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
}

@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();
        }

        @Override
        public boolean isFinished() {
            return false;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setReadListener(ReadListener readListener) {

        }
    };
}

}

新建HttpServletRequestReplacedFilter(过滤器)
package com.xxx.util.core.filter.request;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class HttpServletRequestReplacedFilter implements Filter {

@Override
public void destroy() {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {
    ServletRequest requestWrapper = null;
    if(request instanceof HttpServletRequest) {
        requestWrapper = new RequestReaderHttpServletRequestWrapper((HttpServletRequest) request);
    }
    //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
    // 在chain.doFiler方法中传递新的request对象
    if(requestWrapper == null) {
        chain.doFilter(request, response);
    } else {
        chain.doFilter(requestWrapper, response);
    }
}

@Override
public void init(FilterConfig arg0) throws ServletException {

}

}

最后我们只需要在Application.java中加上如下代码注入过滤器即可
@Bean

public FilterRegistrationBean httpServletRequestReplacedRegistration() {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new HttpServletRequestReplacedFilter());
    registration.addUrlPatterns("/*");
    registration.addInitParameter("paramName", "paramValue");
    registration.setName("httpServletRequestReplacedFilter");
    registration.setOrder(1);
    return registration;
}

如下代码即可在拦截其中获取body且保证了controller中依旧可以再次获取
HttpHelper.getBodyString(request);

相关文章
|
20天前
|
Java Maven
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
在Java项目中,启动jar包时遇到“no main manifest attribute”错误,且打包大小明显偏小。常见原因包括:1) Maven配置中跳过主程序打包;2) 缺少Manifest文件或Main-Class属性。解决方案如下:
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
|
16天前
|
存储 Java BI
java怎么统计每个项目下的每个类别的数据
通过本文,我们详细介绍了如何在Java中统计每个项目下的每个类别的数据,包括数据模型设计、数据存储和统计方法。通过定义 `Category`和 `Project`类,并使用 `ProjectManager`类进行管理,可以轻松实现项目和类别的数据统计。希望本文能够帮助您理解和实现类似的统计需求。
63 17
|
1月前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
145 26
|
2月前
|
XML Java 测试技术
从零开始学 Maven:简化 Java 项目的构建与管理
Maven 是一个由 Apache 软件基金会开发的项目管理和构建自动化工具。它主要用在 Java 项目中,但也可以用于其他类型的项目。
76 1
从零开始学 Maven:简化 Java 项目的构建与管理
|
2月前
|
Java
Java项目中高精度数值计算:为何BigDecimal优于Double
在Java项目开发中,涉及金额计算、面积计算等高精度数值操作时,应选择 `BigDecimal` 而非 `Double`。`BigDecimal` 提供任意精度的小数运算、多种舍入模式和良好的可读性,确保计算结果的准确性和可靠性。例如,在金额计算中,`BigDecimal` 可以精确到小数点后两位,而 `Double` 可能因精度问题导致结果不准确。
|
2月前
|
Java
实现java执行kettle并传参数
实现java执行kettle并传参数
35 1
|
2月前
|
Java Android开发
Eclipse 创建 Java 项目
Eclipse 创建 Java 项目
54 4
|
2月前
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
48 0
|
2月前
|
Java
在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
|
前端开发 JavaScript 关系型数据库
前后端分离 -- SpringBoot + Vue实战项目 部署至阿里云服务器
前后端分离 -- SpringBoot + Vue实战项目 部署至阿里云服务器
3310 2
前后端分离 -- SpringBoot + Vue实战项目 部署至阿里云服务器