Spring MVC 解决request.getInputStream(POST请求)只能读取一次问题(全局替换request)
直奔主题
实现方法:
SpringMVC是通过前端控制器(DispatcherServlet)接收请求进行请求转发的,所以可以从这里入手把request对象替换为自定义的request对象,从而解决request的输入流只能读取一次的问题.
步骤:
1..重写service方法,实现替换request操作
package org.XXX.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.XXX.request.CustomRequest; public class DispatcherServlet extends org.springframework.web.servlet.DispatcherServlet { private static final long serialVersionUID = 6781076086037842254L; @Override protected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { // 全局替换request对象 super.service(new CustomRequest(request), response); } }
将我们自己的前端控制器配置到web.xml中
<servlet> <servlet-name>springmvc</servlet-name> <!-- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> --> <servlet-class>org.XXX.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
至此request替换操作已经完成,下面进入重点.
2.实现自己的HttpServletRequest
package org.XXX.request; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.apache.commons.io.IOUtils; /** * 自定义Request * */ public class CustomRequest extends HttpServletRequestWrapper { private byte[] postBody; public CustomRequest(HttpServletRequest request) { super(request); } @Override public ServletInputStream getInputStream() throws IOException { if (postBody == null) { postBody = IOUtils.toByteArray(super.getInputStream()); } return new CustomServletInputStream(postBody); } /** * 自定义ServletInputStream * */ private static class CustomServletInputStream extends ServletInputStream { private final InputStream is; CustomServletInputStream(byte[] postBody) { if (postBody == null) { postBody = new byte[0]; } this.is = new ByteArrayInputStream(postBody); } @Override public int read() throws IOException { return is.read(); } } }
大功告成!!
最后附上AOP方法中读取post内容的部分代码
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String requestBody = null; if ("POST".equals(request.getMethod())) { // 读取requestBody byte[] bytes = IOUtils.toByteArray(request.getInputStream()); requestBody = new String(bytes,request.getCharacterEncoding()); }else{ Map<String,String[]> parameterMap = request.getParameterMap(); if(parameterMap != null && !parameterMap.isEmpty()){ requestBody = gson.toJson(parameterMap); } } if (requestBody != null && !requestBody.isEmpty()) { logger.info("requestBody: " + requestBody); }