项目上因为有需要需要在拦截器里面获取请求体里面的数据进行数据验证,因为自己定义的controller里面对使用了@RequestBody注解,导致项目报错了报错的内容是:java.lang.IllegalStateException: getReader() has already been called for this request
查阅资料发现request里面的的getReader 和getInputStream因为是以流的方式获取的,读取一次后,后续就不能再用了,解决思路是把流里面的内容提前读取出来存起来,后面每次用到getInputStream和getReader的时候,用存起来的内容做相应的转换就可以了,步骤如下:
第一步:定义一个过滤器,过滤器里面传入自己定义的request,自己定义的request要继承HttpServletRequestWrapper这个包装类,并重写里面的getInputStream和getReader方法
过滤器代码如下:
package com.chinastock.filter;
import com.chinastock.util.CustomHttpServletRequestWrapper;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author zhoule
* @description: 过滤器,处理request
*/
public class IMTAFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(servletRequest instanceof HttpServletRequest) {
requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
}
if(requestWrapper == null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
}
自定义request代码如下:
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
* @author zhoule
* @description: 自定义request wrapper用于对请求体中的报文进行处理
*/
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException
{
super(request);
BufferedReader reader = request.getReader();
try (StringWriter writer = new StringWriter()) {
int read;
char[] buf = new char[1024 * 8];
while ((read = reader.read(buf)) != -1) {
writer.write(buf, 0, read);
}
this.body = writer.getBuffer().toString().getBytes();
}
}
public String getBody(){
return new String(body, StandardCharsets.UTF_8);
}
@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) {
}
public int read() throws IOException
{
return byteArrayInputStream.read();
}
};
}
@Override
public BufferedReader getReader() throws IOException
{
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
第二步自己写项目的拦截器,拦截器的部分代码如下:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request;
String body = wrapper.getBody();
System.out.println(body);
return true;
}