当我开始读取时,为什么InputStreamResource会关闭?

时间:2016-02-09 12:33:17

标签: java mongodb spring-mvc

我有一个存储csv文件的MongoDB和两个微服务(Spring Boot应用程序)。一个微服务处理文件上传并支持将这些文件作为流来获取。其他微服务处理文件。这些微服务是分开的,因为我可能希望以后的方式存储文件,而不是MongoDB,我不想通过它来影响其他服务。

我的问题是,当文件服务将文件作为InputStreamResource返回时,如下所示:

@RequestMapping(value = "/upload/{importId}", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<InputStreamResource> getUploadedFile(@PathVariable("importId") String importId)
        throws ImportFileNotFoundException {
    GridFSDBFile file = FileImportClient.getInstance().getFile(importId);

    return ResponseEntity
            .ok()
            .contentLength(file.getLength())
            .body(new InputStreamResource(file.getInputStream()));
}

我想从流中读取它已经关闭。

ResponseEntity<InputStreamResource> response = restTemplate
            .getForEntity("http://upload-service/upload/" + importId, InputStreamResource.class);
BufferedReader fileReader = new BufferedReader(new InputStreamReader(response.getBody().getInputStream()));
for (CSVRecord record : CSVFormat.DEFAULT.parse(fileReader)) {/*toStuff()*/}

我得到了由解析方法引起的java.io.IOException: Stream closed

如果我只是curl localhost:<port>/upload/<importId>,我会得到整个csv文件。 有谁知道,为什么关闭InputStream以及如何解决这个问题?

堆栈追踪:

java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:170)
at java.io.BufferedInputStream.read(BufferedInputStream.java:336)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.read1(BufferedReader.java:210)
at java.io.BufferedReader.read(BufferedReader.java:286)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.read(BufferedReader.java:182)
at org.apache.commons.csv.ExtendedBufferedReader.read(ExtendedBufferedReader.java:60)
at org.apache.commons.csv.Lexer.nextToken(Lexer.java:89)
at org.apache.commons.csv.CSVParser.nextRecord(CSVParser.java:498)
at org.apache.commons.csv.CSVParser$1.getNextRecord(CSVParser.java:439)
at org.apache.commons.csv.CSVParser$1.hasNext(CSVParser.java:452)
at <mypackage>.<myclass>.process(<myclass>.java:71)

1 个答案:

答案 0 :(得分:4)

我通过此链接找到了解决方案:https://jira.spring.io/browse/SPR-7357

  

[这回答了我的问题]请注意,您不能简单地从提取器返回InputStream,因为在execute方法返回时,底层连接和流已经关闭

     

[这解决了问题]你已经可以通过使用RestTemplate上的execute()方法和ResponseExtractor实现来读取InputStream

我尝试使用ResponseExtractor,现在正在使用它。它看起来像这样:

return restTemplate.execute(new URI("http://<myservice>/upload/" + importId), HttpMethod.GET, null,
            new ResponseExtractor<MyObject>() {
                @Override
                public MyObject extractData(ClientHttpResponse response) throws IOException {
                    CSVParser parse = CSVFormat.DEFAULT.parse(new BufferedReader(new InputStreamReader(response.getBody())));
                    for (CSVRecord record : parse) {/*dostuff*/}
                    return new MyObject();
                }
            });