簡體   English   中英

如何從POST請求中獲取XML並在Servlet過濾器中對其進行修改?

[英]How to get the XML from POST request and modify it in Servlet Filter?

我目前正在處理一個要求,即在請求到達Spring控制器之前,需要在servlet過濾器中獲取XML(從POST請求中獲取),然后在XML請求中處理XML(刪去一些空節點/元素)。過濾,然后調用應繼續進行。

我嘗試了下面的代碼(僅附加了代碼段),並且能夠獲取請求正文(XML)並能夠設置修改后的響應。

    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    if (httpRequest.getMethod().equalsIgnoreCase("POST")) {
      extractDataFromRequest(httpRequest);
      httpResponse.getWriter().write("<root><root>");
    }
    chain.doFilter(request, wrappedResponse);

   public static String extractDataFromRequest(HttpServletRequest request) throws IOException {

    String line;
    StringBuilder builder = new StringBuilder();
    BufferedReader reader = request.getReader();
    while ((line = reader.readLine()) != null) {
      builder.append(line);
    }
    return builder.toString();
  }

但是,spring失敗,但以下例外。

Severe: java.lang.IllegalStateException: PWC3997: getReader() has already been called for this request
    at org.apache.catalina.connector.Request.getInputStream(Request.java:1178)
    at org.apache.catalina.connector.RequestFacade.getInputStream(RequestFacade.java:407)
    at org.springframework.http.server.ServletServerHttpRequest.getBody(ServletServerHttpRequest.java:165)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:120)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:100)

我正在尋找專家對此要求的具體實現。

您不能兩次使用InputStream,需要創建一個包裝類,以保留InputStream的可重復副本。

public class ReadTwiceHttpServletRequestWrapper extends HttpServletRequestWrapper {

private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

public ReadTwiceHttpServletRequestWrapper(HttpServletRequest request) {
    super(request);
    try {
        IOUtils.copy(request.getInputStream(), outputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(outputStream.toByteArray())));
}

@Override
public ServletInputStream getInputStream() throws IOException {
    final ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
    return new ServletInputStream() {

        @Override
        public int readLine(byte[] b, int off, int len) throws IOException {
            return inputStream.read(b, off, len);
        }

        @Override
        public boolean isFinished() {
            return inputStream.available() > 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener arg0) {
            // TODO Auto-generated method stub
        }

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

public void setBody(String body) {
    outputStream = new ByteArrayOutputStream();
    try {
        outputStream.write(body.getBytes());
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public String getBody() {
    return new String(outputStream.toByteArray());
}

}

然后,您需要使用鏈中第一個過濾器進行初始化。

public class ReadTwiceFilter implements Filter {

@Override
public void destroy() {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

    ReadTwiceHttpServletRequestWrapper readTwiceHttpServletRequestWrapper = new ReadTwiceHttpServletRequestWrapper(
            (HttpServletRequest) request);

    String newBody = readTwiceHttpServletRequestWrapper.getBody().replace("<soap:studentId>1</soap:studentId>", "<soap:studentId>2</soap:studentId>");
    readTwiceHttpServletRequestWrapper.setBody(newBody);

    chain.doFilter(readTwiceHttpServletRequestWrapper, response);
}

@Override
public void init(FilterConfig arg0) throws ServletException {
}

}

在過濾器getReader實現更改為使用getInputStream而不是getReader方法。 當整個實現同時調用ServletRequest的getReader和getInputStream方法時,就會出現此問題。

javadoc中所述 ,只能調用其中之一。 查看堆棧跟蹤; 控制器(spring mvc)正在對其上調用getInputStream,因此已失敗,並顯示一條消息getReader() has already been called...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM