如何在过滤器中获取HttpServletRequest的getInputStream / getParameter而不消耗它?

时间:2016-02-25 10:33:37

标签: servlets servlet-filters query-parameters

有没有办法在过滤器中读取您的请求正文而不会破坏您的控制器?

那是:

  • 使用@RequestParam或方法getParameter(String name)
  • 获取参数的可能性
  • 即使您已经在过滤器中需要,也可以在控制器中获取您的请求的InputStream。

1 个答案:

答案 0 :(得分:0)

我从这篇文章中获得启发:Get the POST request body from HttpServletRequest

然后复制然后缓存正文,然后在属性formParameters中提取并存储参数图。

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {

    private final FormHttpMessageConverter formConverter = new AllEncompassingFormHttpMessageConverter();
    MultiValueMap<String, String> formParameters;
    private ByteArrayOutputStream cachedBytes;

    public MultiReadHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        HttpInputMessage inputMessage = new ServletServerHttpRequest(this) {
            @Override
            public InputStream getBody() throws IOException {
                return getInputStream();
            }
        };
        formParameters = formConverter.read(null, inputMessage);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (cachedBytes == null)
            cacheInputStream();

        return new CachedServletInputStream();
    }

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

    @Override
    public String getParameter(String name) {
        String queryStringValue = super.getParameter(name);
        String formValue = this.formParameters.getFirst(name);
        return (queryStringValue != null) ?  queryStringValue : formValue;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> result = new LinkedHashMap<>();
        Enumeration<String> names = this.getParameterNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            result.put(name, this.getParameterValues(name));
        }
        return result;
    }

    @Override
    public Enumeration<String> getParameterNames() {
        Set<String> names = new LinkedHashSet<>();
        names.addAll(Collections.list(super.getParameterNames()));
        names.addAll(this.formParameters.keySet());
        return Collections.enumeration(names);
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] queryStringValues = super.getParameterValues(name);
        List<String> formValues = this.formParameters.get(name);
        if (formValues == null) {
            return queryStringValues;
        }
        else if (queryStringValues == null) {
            return formValues.toArray(new String[formValues.size()]);
        }
        else {
            List<String> result = new ArrayList<>();
            result.addAll(Arrays.asList(queryStringValues));
            result.addAll(formValues);
            return result.toArray(new String[result.size()]);
        }
    }

    private void cacheInputStream() throws IOException {
/* Cache the inputstream in order to read it multiple times. For
 * convenience, I use apache.commons IOUtils
 */
        cachedBytes = new ByteArrayOutputStream();
        IOUtils.copy(super.getInputStream(), cachedBytes);
    }

    /* An inputstream which reads the cached request body */
    public class CachedServletInputStream extends ServletInputStream {
        private ByteArrayInputStream input;

        public CachedServletInputStream() {
  /* create a new input stream from the cached request body */
            input = new ByteArrayInputStream(cachedBytes.toByteArray());
        }

        @Override
        public int read() throws IOException {
            return input.read();
        }
    }
}