如何从POST请求中获取XML并在Servlet Filter中修改它? [英] How to get the XML from POST request and modify it in Servlet Filter?

查看:402
本文介绍了如何从POST请求中获取XML并在Servlet Filter中修改它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在处理一个需求,我需要在请求到达Spring控制器之前在servlet过滤器中获取XML(来自POST请求),然后我需要处理XML(切断一些空节点/元素) )在过滤器中然后调用应该继续进行。

I am currently working on a requirement where I need to get the XML (from POST request) in the servlet filter before the request reaches to the Spring controller and then I need to process the XML (cut off some empty nodes/elements) in the filter and then the call should proceed further.

我尝试了下面的代码(仅附加了代码片段),我能够获得请求体(XML)和能够设置修改后的响应。

I tried the below code (attached only snippet) and I was able to get the request body (XML) and able to set the modified response.

    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();
  }

然而,春天因以下异常而失败。

However, spring failed with the following exception.

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)

我正在寻找一个具体的实现来自专家的这一要求。

I am looking for a concrete implementation for this requirement from experts.

推荐答案

你不能两次使用InputStream,你需要创建一个包装类来保存InputStream的可重复副本。

You can't use the InputStream twice, you need to create a wrapper class which keeps a repeatable copy of the 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());
}

}

然后你需要用一个首先在链中的Filter初始化它。

Then you need to initialise that with a Filter which is first in the chain.

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 {
}

}

这篇关于如何从POST请求中获取XML并在Servlet Filter中修改它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆