目录
1、背景
2、解决方案
2.1、自定义HttpServletRequestWrapper
2.2、JsonRequestHeaderParamsHelper
2.3、HttpServletRequestReplacedFilter
2.4、使用
1、背景
当前系统Content-Type为application/json,参数接收方式采用@RequestBody和@RequestParam,但Interceptor拦截器和Aspect切面中存在再次调用request获取其中请求参数或者请求头等操作,导致报错getReader()和getInputStream()只能调用一次(getInputStream() has already been called for this request)。
2、解决方案
2.1、自定义HttpServletRequestWrapper
由于请求信息存储在流中,只能调用一次,因此将其存储到字节数组中,保证之后调用getReader()和getInputStream()均通过body数组来获取数据。
public class BodyReaderHttpServletRequestWrapper extends
HttpServletRequestWrapper {
private final byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
throws IOException {
super(request);
body = JsonRequestHeaderParamsHelper.bufferReaderToString(request.getReader()).getBytes();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return byteArrayInputStream.read();
}
};
}
}
2.2、JsonRequestHeaderParamsHelper
@Slf4j
public class JsonRequestHeaderParamsHelper {
public static JSONObject parseHeader(ServletRequest request) throws IOException {
return JSON.parseObject(bufferReaderToString(request.getReader()));
}
public static String bufferReaderToString(BufferedReader reader) throws IOException {
StringBuilder sb = new StringBuilder();
try {
char[] buff = new char[1024];
int len;
while ((len = reader.read(buff)) != -1) {
sb.append(buff, 0, len);
}
} catch (IOException e) {
log.error("bufferReaderToString error", e);
}
return sb.toString();
}
}
2.3、HttpServletRequestReplacedFilter
通过Order(0)使其最优先加载,保证所有请求都先将request替换为自定义的。
此处的init()和destroy()方法不要使用super.init(),务必清空idea自动生成的内容。
@Slf4j
@Order(value = 0)
@WebFilter(filterName = "httpServletRequestReplacedFilter", urlPatterns = "/*")
public class HttpServletRequestReplacedFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("进入HttpServletRequestReplacedFilter");
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 init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
2.4、使用
之后就可以愉快地使用request.getParameter,@RequestBody等等了。
附上get和post手动获取请求参数的方法:
if("GET".equals(request.getMethod())|| "DELETE".equals(request.getMethod())) {
JSONObject jsonObject = JSONObject.fromObject(request.getParameterMap());
params=jsonObject.toString();
log.info("get请求参数为:{}", params);
}else {
com.alibaba.fastjson.JSONObject jsonObject =JsonRequestHeaderParamsHelper.parseHeader(request);
params=jsonObject.toJSONString();
log.info("post请求参数为:{}",params);
}
如果对你有帮助,点赞、收藏、关注是我更新的动力!
往期精彩:
#11vue3中使用el-dialog展示与关闭交由父组件控制的写法-CSDN博客文章浏览阅读1k次,点赞40次,收藏28次。vue3中使用elementplus的el-dialog展示与关闭交由父组件控制的写法,分两种方法,使用difineExpose或者defineEmits实现https://blog.csdn.net/weixin_42718399/article/details/136155379?spm=1001.2014.3001.5501#10外部网页跳转vue3+SpringMVC解码GBK编码的参数-CSDN博客文章浏览阅读2.2k次,点赞64次,收藏18次。外部网页跳转vue3页面解码GBK编码的参数问题(包括乱码、解码失败、无法进入页面、URI malformed等问题)https://blog.csdn.net/weixin_42718399/article/details/135995885?spm=1001.2014.3001.5501#6解析@PreAuthorize以及其中的Spel-CSDN博客文章浏览阅读1.2k次,点赞41次,收藏18次。#6解析@PreAuthorize以及其中的Spel _@preauthorizehttps://blog.csdn.net/weixin_42718399/article/details/135558235?spm=1001.2014.3001.5501#2Vite+Vue3+SpringMVC前后端分离 解决跨域问题和session每次请求不一致问题_vue3前后端分离跨域问题-CSDN博客文章浏览阅读1.1k次,点赞37次,收藏15次。Vite+Vue3+SpringMVC前后端分离通过vite/nginx解决跨域问题和session一致性问题_vue3前后端分离跨域问题https://blog.csdn.net/weixin_42718399/article/details/135388463?spm=1001.2014.3001.5501