解决HttpServletRequest请求流只能读取一次的问题

问题:

有时候我们需要在拦截器中获取请求参数进行判断,普通表单提交的参数可以通过httpServletRequest.getParameterMap()获取,但是JSON数据需要从HttpServletRequest的流中读取。问题来了,HttpServletRequest的流只能读取一次,如果在拦截器中读取了流,那么继续向下执行到controller将无法获取到Json参数,同时会提示流已关闭。

解决方法:

我们可以利用HttpServletRequestWrapper来包装HttpServletRequest,将请求体中的流copy一份,覆写getInputStream()和getReader()方法供外部使用,同时自己定义一个getRequestBody()方法,用于直接获取Json参数。每次调用覆写后的getInputStream()方法都是从复制出来的二进制数组中进行获取,这个二进制数组在对象存在期间一直存在,这样就实现了流的重复读取。

自定义包装类:

public class RequestWrapper extends HttpServletRequestWrapper {
    private final byte[] requestBody;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody =  StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody);
        return new ServletInputStream() {
            public boolean isFinished() {
                return false;
            }
            public boolean isReady() {
                return false;
            }
            public void setReadListener(ReadListener readListener) {}
            public int read() {
                return byteArrayInputStream.read();
            }
        };

    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }


    public String getRequestBody() {
        return new String(this.requestBody);
    }
}

过滤器中启用包装类:

public class JsonFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //请求参数为JSON类型,则使用自定义包装
        if(request instanceof HttpServletRequest
                && "application/json".equals(((HttpServletRequest)request).getHeader("Content-Type"))) {
            chain.doFilter(new RequestWrapper((HttpServletRequest)request), response);
        } else {
            chain.doFilter(request, response);
        }
    }
    public void destroy() {
    }
}

拦截器中获取JSON参数:

public boolean repeatDataValidator(HttpServletRequest httpServletRequest) throws IOException {
		String params = "";
		if("application/json".equals(httpServletRequest.getHeader("Content-Type"))){
             //通过方法直接获取JSON参数
			params = ((RequestWrapper)httpServletRequest).getRequestBody();
		}else {
			params = JSONObject.toJSONString(httpServletRequest.getParameterMap());
		}
         
         ..................自定义处理
  
  }

你可能感兴趣的:(Java,java,java-ee)