Java过滤器在控制器之前输入XML

时间:2017-11-24 14:14:40

标签: xml spring-mvc controller inputstream servlet-filters

我想验证通过http POST请求收到的XML到我的Spring MVC Controller,但是我需要将它验证到ServletFilter中。

在输入流上使用DocumentBuilderFactory没问题:我在ServletFilter中正确解析和分析输入。

通过我的过滤器,调试器不会让我看到它在各种库和类中发生了什么,但是我无法登陆Spring Controller并直接得到" 400 Bad Request"作为回应。

没有这行代码(并且没有对xml文件进行所有后续解析和验证)在我的过滤器中

Document doc = builder.parse(xml);

请求对Spring Controller没有任何问题,它将输入XML映射到名为 RequestModel.java的

的对象

但是当我在过滤器中添加解析和验证时,导航会在登陆Controller之前阻塞,而不会抛出任何异常。

这是让我在过滤器中调用失败的片段:

InputStream xml = request.getInputStream();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    try {
        DocumentBuilder builder = factory.newDocumentBuilder();

        Document doc = builder.parse(xml); //ADDING THIS LINE IT FAILS!

        //method continues with  xml parsing and validation...

这是我的Controller方法的开始(通过解析,之前导航被阻止):

@Controller
@EnableSwagger2
@RequestMapping("/listaprocessi")
@Api(description = "Lista processi ammessi", tags="Lista processi")
public class ListaProcessiController {

    @RequestMapping(produces = MediaType.APPLICATION_XML_VALUE, consumes = MediaType.APPLICATION_XML_VALUE, method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value="Lista processi")
    public BusinessListaProcessiModel listaProcessi(@RequestBody RequestModel requestModel) throws RemoteException{ ...}

是否因为分析输入过滤器必须等到流关闭?你有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您只能处理一次ServletInputStream。因此,当您在过滤器中处理它时,Spring MVC框架无法为您的控制器处理它。

我遇到过很多次。为了解决这个问题,我将HttpServletRequest包装在一个允许重新读取InputStream的新类(见下文)中。如果您将HttpServletRequest包装在下面的类的实例中并在DocumentBuilder中使用它并将其传递给Filter的doFilter方法,那么您应该很好。

public class CachingRequestWrapper extends HttpServletRequestWrapper {

    private final String cachedMsgBody;

    public CachingRequestWrapper(HttpServletRequest request) throws HttpErrorException {
        super(request);
        cachedMsgBody = ServletUtils.extractMsgBodyToString(request);
    }

    public CachingRequestWrapper(HttpServletRequest request, String msgBody) throws HttpErrorException {
        super(request);
        cachedMsgBody = msgBody;
    }

    public String getCachedMsgBody() {
        return cachedMsgBody;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(cachedMsgBody.getBytes()));
        return new BufferedReader(isr);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        ServletInputStream sis = new ServletInputStream() {
            private int i = 0;
            byte[] msgBodyBytes = cachedMsgBody.getBytes();

            @Override
            public int read() throws IOException {
                byte b;
                if (msgBodyBytes.length > i) {
                    b = msgBodyBytes[i++];
                } else {
                    b = -1;
                }
                return b;
            }

            public boolean isFinished() {
                return i == msgBodyBytes.length;
            }

            public boolean isReady() {
                return true;
            }

            public void setReadListener(ReadListener rl) {
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
            }
        };

        return sis;
    }

}

参考:http://stackoverflow.com/a/6322667/1490322