最近使用spring mvc做项目,数据格式是json,有一个功能是实现记录请求的参数,而请求的参数是整个RequestBody,Controller里是用过@RequestBody获取的。实现方法是通过一个Filter读取整个RequestBody并记录。但是这时就遇到一个问题,ServletRequest的getReader()和getInputStream()两个方法只能被调用一次,而且不能两个都调用。那么如果Filter中调用了一次,在Controller里面就不能再调用了。查看了下ServletRequest的说明,如下:
- /**
- * Retrieves the body of the request as binary data using
- * a {@link ServletInputStream}. Either this method or
- * {@link #getReader} may be called to read the body, not both.
- *
- * @return a {@link ServletInputStream} object containing
- * the body of the request
- *
- * @exception IllegalStateException if the {@link #getReader} method
- * has already been called for this request
- *
- * @exception IOException if an input or output exception occurred
- *
- */
- public ServletInputStream getInputStream() throws IOException;
- /**
- * Retrieves the body of the request as character data using
- * a <code>BufferedReader</code>. The reader translates the character
- * data according to the character encoding used on the body.
- * Either this method or {@link #getInputStream} may be called to read the
- * body, not both.
- *
- *
- * @return a <code>BufferedReader</code>
- * containing the body of the request
- *
- * @exception UnsupportedEncodingException if the character set encoding
- * used is not supported and the
- * text cannot be decoded
- *
- * @exception IllegalStateException if {@link #getInputStream} method
- * has been called on this request
- *
- * @exception IOException if an input or output exception occurred
- *
- * @see #getInputStream
- *
- */
- public BufferedReader getReader() throws IOException;
两个方法都注明方法只能被调用一次,由于RequestBody是流的形式读取,那么流读了一次就没有了,所以只能被调用一次。既然是因为流只能读一次的原因,那么只要将流的内容保存下来,就可以实现反复读取了。
实现方法:先将RequestBody保存为一个byte数组,然后通过Servlet自带的HttpServletRequestWrapper类覆盖getReader()和getInputStream()方法,使流从保存的byte数组读取。然后再Filter中将ServletRequest替换为ServletRequestWrapper。代码如下:
BodyReaderHttpServletRequestWrapper类包装ServletRequest,将流保存为byte[],然后将getReader()和getInputStream()方法的流的读取指向byte[]
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import javax.servlet.ServletInputStream;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletRequestWrapper;
- import jodd.JoddDefault;
- import jodd.io.StreamUtil;
- public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
- private final byte[] body;
- public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
- throws IOException {
- super(request);
- body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);
- }
- @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();
- }
- };
- }
- }
在Filter中将ServletRequest替换为ServletRequestWrapper
- public class HttpServletRequestReplacedFilter implements Filter {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- //Do nothing
- }
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- 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 destroy() {
- //Do nothing
- }
- }
(文/liwx2000)
本文来源:http://liwx2000.iteye.com/blog/1542431
如果给你带来帮助,欢迎微信或支付宝扫一扫,赞一下。


从流中获取消息体的方法:
public static String getBodyString(ServletRequest request) {
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();
}