如何将大型输入流发送到Spring REST服务?

时间:2014-01-15 18:38:32

标签: java spring rest spring-mvc

在嵌入式Jetty容器中运行Spring Rest应用程序。 在客户端我使用RestTemplate(尝试)。

用例:

有一个InputStream(我没有文件),我想将它发送到REST服务。

InputStream可能非常大(没有byte []!)。

到目前为止我尝试过:

StandardServletMultipartResolver 添加到Dispatcher上下文中;

执行servlet注册时:

ServletRegistration.Dynamic dispatcher = ...
MultipartConfigElement multipartConfigElement = new MultipartConfigElement("D:/temp");
dispatcher.setMultipartConfig(multipartConfigElement);

在客户端:

restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
        MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
        parts.add("attachmentData", new InputStreamResource(data) {
            // hacks ...
            @Override
            public String getFilename() {
                //avoid null file name
                return "attachment.zip";
            }

            @Override
            public long contentLength() throws IOException {
                // avoid calling getInputStream() twice
                return -1L;
            }
        }
ResponseEntity<Att> saved = restTemplate.postForEntity(url, parts, Att.class)

在服务器上:

    @RequestMapping("/attachment")
    public ResponseEntity<Att> saveAttachment(@RequestParam("attachmentData") javax.servlet.http.Part part) {
        try {
            InputStream is = part.getInputStream();
            // consume is
            is.close();
            part.delete();
            return new ResponseEntity<Att>(att, HttpStatus.CREATED);
        } 
    }

发生了什么: 上载的InputStream已成功存储在已配置的临时文件夹(MultiPart1970755229517315824)中,零件参数在处理程序方法中正确注入。

delete()方法不会删除文件(smth仍然打开了句柄)。

无论如何,它看起来很丑陋。

是否有更顺畅的解决方案?

2 个答案:

答案 0 :(得分:3)

您想要使用HTTP的Chunked Transfer Coding。您可以通过设置SimpleClientHttpRequestFactory.setBufferRequestBody(false)启用该功能。请参阅SPR-7909

答案 1 :(得分:0)

您应该使用byte [],并在Web服务周围编写一个包装器,以实际发送块中的“大字符串”。在webservice中添加一个参数,该参数将指示内容的“contentID”,以便另一方知道该部分属于哪个半满的“桶”。另一个参数“chunkID”将有助于对另一侧的块进行排序。最后,如果你发送的是最后的东西,第三个参数“isFinalChunk”将被设置。这是非常奇特的功能,可以在不到100行代码中实现。

唯一的问题是你最终会对网络服务进行“n”调用,而不是只调用一次,这会聚合连接延迟等。对于实时的东西,需要更多的网络QoS,否则你应该没事。

我认为这更简单,一旦你有自己的类包装器来做这个简单的切割和粘合,如果你的服务器可以处理多个webservice调用,它可以在很大程度上扩展。