springboot 获取到的inputStream为空的问题
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为空的问题的更多相关文章
- springboot 获取控制器参数的几种方式
这里介绍springboot 获取控制器参数有四种方式 1.无注解下获取参数 2.使用@RequestParam获取参数 3.传递数组 4.通过URL传递参数 无注解下获取参数无注解下获取参数,需要控 ...
- request.getParameter("name")获取参数为null和空字符串的区别
1.获取到的值为空字符串 当url里有name属性,但是没有值的时候,后台用request.getParameter("name")获取到的是空字符串 2.获取到的值为null 当 ...
- 使用paginate方法分页无法判断获取的数据是否为空
问题:使用paginate方法分页无法判断获取的数据是否为空,在模板里面无法判断数据是否为空,比如在商品列表当中,当没有商品时无法判断生成的对象为空,所有就什么都不显示了. 解决办法: $newsDa ...
- springboot获取项目的绝对路径和根目录
springboot获取当前项目路径的地址 System.getProperty("user.dir") 输出目录: G:\outshine\wangsoso //获取class ...
- SpringBoot获取http请求参数的方法
SpringBoot获取http请求参数的方法 原文:https://www.cnblogs.com/zhanglijun/p/9403483.html 有七种Java后台获取前端传来参数的方法,稍微 ...
- SpringBoot获取配置文件,就这么简单。
在讲SpringBoot 获取配置文件之前我们需要对SpringBoot 的项目有一个整体的了解,如何创建SpringBoot 项目,项目结构等等知识点,我在这里就不一一讲述了,没有学过的小伙伴可以自 ...
- Java bean 链式获取成员变量无需判空的工具设计
Java bean 链式获取成员变量无需判空的工具设计 本篇文章已发布至公众号 Hollis 对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者 ...
- @PostConstruct +getapplicationcontext.getbean springboot获取getBean
Componentpublic class SpringContextUtils implements ApplicationContextAware { public static Applicat ...
- SpringBoot获取resource下证书失败
1.第一种失败的情况: 本来使用Spring的上下文容器获取文件,将证书文件放在resource下,编译后获取文件会出现报错 java.security.spec.InvalidKeySpecE ...
随机推荐
- phpmyadmin 在服务起上检测到错误,请查看窗口底部
使用phpmyadmin一直提示这个警告,看着难受: 解决: 修改文件:/etc/phpmyadmin/config.inc.php 在最后添加这一句, $cfg['SendErrorReports' ...
- Java学习——单元测试JUnit
Java学习——单元测试JUnit 摘要:本文主要介绍了什么是单元测试以及怎么进行单元测试. 部分内容来自以下博客: https://www.cnblogs.com/wxisme/p/4779193. ...
- Flask--闪现、中间件、多app应用
目录 闪现 源码 案例 中间件 自定义局部中间件 自定义全局装饰器 多app应用 闪现 flask提供了一个非常有用的flash()函数,它可以用来"闪现"需要提示给用户的消息,比 ...
- 学习shiro第三天
今天比较晚,所以只看了shiro的认证策略Authentication Strategy,下面讲讲shiro的三种认证策略. 1.AtLeastOneSuccessfulStrategy:这个是shi ...
- flink KMeans算法实现
更正:之前发的有两个错误. 1.K均值聚类算法 百度解释:k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类 ...
- LeetCode——Employees Earning More Than Their Managers
The Employee table holds all employees including their managers. Every employee has an Id, and there ...
- Rust中的闭包
这个功能有点高级, 暂时理解不完全, 先把代码练正确吧. use std::thread; use std::time::Duration; struct Cacher<T> where ...
- 2020年第二期《python接口自动化+测试开发》课程,已开学!
2020年第二期<python接口自动化+python测试开发>课程,12月15号开学! 主讲老师:上海-悠悠 上课方式:QQ群视频在线教学,方便交流 本期上课时间:12月15号-3月29 ...
- 深入理解defer(上)defer基础
深入理解 defer 分上下两篇文章,本文为上篇,主要介绍如下内容: 为什么需要 defer: defer 语法及语义: defer 使用要点: defer 语句中的函数到底是在 return 语句之 ...
- 在 Oracle 中使用正则表达式
Oracle使用正则表达式离不开这4个函数: 1.regexp_like 2.regexp_substr 3.regexp_instr 4.regexp_replace 看函数名称大概就能猜到有什么用 ...