springboot在接收http请求的时候读取的request的inputStream,造成我们想自己读取inputStream的时候发现inputStream已经无法读取了。

为了读取inputStream,我们应该在springboot读取之前把inputStream的内容暂存先来。

1 这里要使用一个类HttpServletRequestWrapper,我们写一个类继承这个类,把传入的request中的inputStream转为byte[] 暂存下来,重写其中的getInputStream方法,每次返回由暂存的byte转换而来的 inputStream。

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors; import javax.servlet.ReadListener;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.Part; import org.springframework.web.bind.annotation.RequestMethod; public class InputStreamHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] streamBody;
private static final int BUFFER_SIZE = 4096; public InputStreamHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
byte[] bytes = new byte[0];
String uri = request.getRequestURI();
if (Objects.isNull(request.getHeader("Content-Type")) || request.getHeader("Content-Type").contains("multipart/form-data;")) {
bytes = inputStream2Byte(request.getInputStream());
} else if (isFormPost(request)) {
// 从ParameterMap获取参数,并保存以便多次获取
bytes = params2Byte(request);
} else {
bytes = inputStream2Byte(request.getInputStream());
} streamBody = bytes;
// this.setRequest(this);
} private boolean isFormPost(HttpServletRequest request) {
return RequestMethod.POST.name().equals(request.getMethod());
} private byte[] params2Byte(HttpServletRequest request) {
byte[] bytes = request.getParameterMap().entrySet().stream().map(entry -> {
String result;
String[] value = entry.getValue();
if (value != null && value.length > 1) {
result = Arrays.stream(value).map(s -> entry.getKey() + "=" + s).collect(Collectors.joining("&"));
} else {
result = entry.getKey() + "=" + value[0];
} return result;
}).collect(Collectors.joining("&")).getBytes();
return bytes;
} private byte[] inputStream2Byte(InputStream inputStream) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[BUFFER_SIZE];
int length;
while ((length = inputStream.read(bytes, 0, BUFFER_SIZE)) != -1) {
outputStream.write(bytes, 0, length);
} return outputStream.toByteArray();
} @Override
public ServletInputStream getInputStream() throws IOException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(streamBody); return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
} @Override
public boolean isReady() {
return false;
} @Override
public void setReadListener(ReadListener listener) { } @Override
public int read() throws IOException {
return inputStream.read();
}
};
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}

2.这里要使用一个神奇的filter:HiddenHttpMethodFilter

在这个类中调用之前定义的 InputStreamHttpServletRequestWrapper类,并把实例化之后的类传入以后的filter中,这样以后所有的 ServletRequest 都是我们自己定义的了。

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.filter.OncePerRequestFilter; import com.esri.rest.configure.helper.InputStreamHttpServletRequestWrapper; public class InputStreamWrapperFilter extends HiddenHttpMethodFilter { @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { ServletRequest servletRequest = new InputStreamHttpServletRequestWrapper(request); filterChain.doFilter(servletRequest, response); } }

3,最后一步:把filter加入springboot 配置

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.HiddenHttpMethodFilter; import com.esri.rest.filter.InputStreamWrapperFilter; @Configuration
public class RequestConfig { @Bean
@Order(1)
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new InputStreamWrapperFilter();
}
}

springboot 获取到的inputStream为空的问题的更多相关文章

  1. springboot 获取控制器参数的几种方式

    这里介绍springboot 获取控制器参数有四种方式 1.无注解下获取参数 2.使用@RequestParam获取参数 3.传递数组 4.通过URL传递参数 无注解下获取参数无注解下获取参数,需要控 ...

  2. request.getParameter("name")获取参数为null和空字符串的区别

    1.获取到的值为空字符串 当url里有name属性,但是没有值的时候,后台用request.getParameter("name")获取到的是空字符串 2.获取到的值为null 当 ...

  3. 使用paginate方法分页无法判断获取的数据是否为空

    问题:使用paginate方法分页无法判断获取的数据是否为空,在模板里面无法判断数据是否为空,比如在商品列表当中,当没有商品时无法判断生成的对象为空,所有就什么都不显示了. 解决办法: $newsDa ...

  4. springboot获取项目的绝对路径和根目录

    springboot获取当前项目路径的地址 System.getProperty("user.dir") 输出目录:  G:\outshine\wangsoso //获取class ...

  5. SpringBoot获取http请求参数的方法

    SpringBoot获取http请求参数的方法 原文:https://www.cnblogs.com/zhanglijun/p/9403483.html 有七种Java后台获取前端传来参数的方法,稍微 ...

  6. SpringBoot获取配置文件,就这么简单。

    在讲SpringBoot 获取配置文件之前我们需要对SpringBoot 的项目有一个整体的了解,如何创建SpringBoot 项目,项目结构等等知识点,我在这里就不一一讲述了,没有学过的小伙伴可以自 ...

  7. Java bean 链式获取成员变量无需判空的工具设计

    Java bean 链式获取成员变量无需判空的工具设计 本篇文章已发布至公众号 Hollis 对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者 ...

  8. @PostConstruct +getapplicationcontext.getbean springboot获取getBean

    Componentpublic class SpringContextUtils implements ApplicationContextAware { public static Applicat ...

  9. SpringBoot获取resource下证书失败

    1.第一种失败的情况:    本来使用Spring的上下文容器获取文件,将证书文件放在resource下,编译后获取文件会出现报错 java.security.spec.InvalidKeySpecE ...

随机推荐

  1. CMake编译的VS工程,安装时遇到错误:error MSB3073: 命令“setlocal

    错误提示 70>CMake Error at src/base/cmake_install.cmake:63 (file): 70> file INSTALL cannot find 70 ...

  2. delphi FillChar的用法(转)

    delphi FillChar的用法(转) (2012-12-24 15:12:06) 转载▼ 标签: it 分类: delphi7 FillChar的用法(delphi) Fillchar是Turb ...

  3. SWPUCTF 2019 web

    web1 知识点 ## information_schema绕过 ##无列名注入 注入点在广告申请广告名字处,申请广告名为 查看广告详细返回错误 接下来就是常规的union注入的套路,但是发现or被过 ...

  4. iOS开发之--为UITextField监听数值变化的三种方法

    项目中有个验证码输入直接验证跳转页面,用的RAC来监听textfield的输入值,如下: @weakify(self); [self.codeView.textField.rac_textSignal ...

  5. IPv6地址类型和操作

    IPv6地址的号段划分和前缀表示法: IPv6拥有128位巨大的地址空间,对于那么大的空间,也不是随意的划分,而是使用按照bit位进行号段划分 地址结构图 全局路由前缀 (48位) 子网ID (16位 ...

  6. DjangoForm 提交验证

    用户提交数据的验证 1.创建模版 -- class LoginForm(forms.Form):.... 2.将请求交给模版,创建一个对象 -- obj = LoginForm(request.POS ...

  7. nrm : 无法加载文件 C:\Users\TANG\AppData\Roaming\npm\nrm.ps1,因为在此系统上禁止运行脚本。

    1.win+s 搜索powershell 以管理身份运行 2.使用set-ExecutionPolicy RemoteSigned命令将计算机上的执行策略更改为 RemoteSigned,输入Y确定 ...

  8. 流程及迭代驱动测试管理软件, itest 发布到开源中国

    itest 源码已发布到码云 ,项目已被开源中国收录!详见  https://www.oschina.net/p/itest-cn 测试人自己开发,汇聚10年沉淀,独创流程驱动测试.度量展现测试人价值 ...

  9. Rust中的函数调用

    注意区别语句和表达式哟. Rust是一门基于表示式的语言,牢记!!! fn main() { println!("Hello world!"); another_function( ...

  10. linux基础-ssh服务

    SSH ssh 服务是实现管路服务器的一种方式: 本地管理(安装系统,故障修复),ssh 远程连接 linux 可以是实现远程连接的方式:ssh 命令 windows 可以实现远程连接方式: xshe ...