问题:在使用SpringMVC拦截器获取POST请求中的JSON信息的时候,使用request.getReader()方法获取JSON信息后,POST请求就不往下走了,
原因:
1. 一个Reader对象在被读取完成后,将无法被再次读取,始终返回-1;
2. POST也是一种流,所以使用Reader方法后,POST请求返回true也不往下走了
解决方案:使用HttpServletRequestWrapper来包装HttpServletRequest,在BodyReaderHttpServletRequestWrapper中初始化读取request的Reader数据,以byte[]形式缓存在其中,然后在Filter中将request转换为包装过的request;代码如下:
public class HttpServletRequestReplacedFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
System.out.println(httpServletRequest.getContentType());
System.out.println(httpServletRequest.getContextPath());
System.out.println(httpServletRequest.getRemoteHost());
System.out.println(httpServletRequest.getMethod());
if ("POST".equals(httpServletRequest.getMethod().toUpperCase())
) {
//&& httpServletRequest.getContentType().equalsIgnoreCase(
// "application/json")
requestWrapper = new BodyReaderHttpServletRequestWrapper(
(HttpServletRequest) request);
}
}
if (requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
public class BodyReaderHttpServletRequestWrapper extends
HttpServletRequestWrapper {
private final byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
Enumeration e = request.getHeaderNames() ;
while(e.hasMoreElements()){
String name = (String) e.nextElement();
String value = request.getHeader(name);
}
body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
}
@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();
}
};
}
@Override
public String getHeader(String name) {
return super.getHeader(name);
}
@Override
public Enumeration<String> getHeaderNames() {
return super.getHeaderNames();
}
@Override
public Enumeration<String> getHeaders(String name) {
return super.getHeaders(name);
}
}
public class HttpHelper {
/**
* 获取请求Body
*
* @param request
* @return
*/
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();
}
}
web.xml配置文件
<filter>
<filter-name>HttpServletRequestReplacedFilter</filter-name>
<filter-class>com.xxx.xxx.xxx.xxx.util.HttpServletRequestReplacedFilter</filter-class>
<!-- <init-param> -->
<!-- <param-name>encoding</param-name> -->
<!-- <param-value>utf-8</param-value> -->
<!-- </init-param> -->
</filter>
<filter-mapping>
<filter-name>HttpServletRequestReplacedFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- <filter-mapping> -->
<!-- <filter-name>CORS</filter-name> -->
<!-- <url-pattern>/*</url-pattern> -->
<!-- </filter-mapping> -->
这样运行的时候就会先走Filter再走springmvc的拦截器了,就可以多次读取了