java - 如何从 POST 请求获取 XML 并在 Servlet Filter 中修改它?

标签 java spring spring-mvc servlets servlet-filters

我目前正在处理一个需求,在请求到达 Spring Controller 之前,我需要在 servlet 过滤器中获取 XML(来自 POST 请求),然后我需要处理 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 {
}

}

关于java - 如何从 POST 请求获取 XML 并在 Servlet Filter 中修改它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38614799/

相关文章:

java - 如何为需要验证第三方生成的 JWT token 且用户没有密码的 rest api 配置 spring http 安全性?

java - 禁用 Spring @Autowired 按名称回退

spring - 类似 HQL 的运算符,用于不区分大小写的搜索

java - 使用打开的 CSV Writer 从 java 中的 bean 对象生成 txt 文件时添加了额外的回车符

java - GridBagLayout 显示元素不正确

java - 从 PHP 脚本调用 Java 时出现问题

Spring Data Neo4j - 找不到 NodeImpl#0 的 '__type__' 属性

java - 控制台中的 Chrome 驱动程序信息

java - Spring Boot 忽略 Rest Controller 中的 Jackson 注释

mysql - 具有多个类的 RowMapper