Java 从SpringMVC端点流式传输动态图像,而不将其保存在内存中

Java 从SpringMVC端点流式传输动态图像,而不将其保存在内存中,java,spring,spring-mvc,amazon-s3,inputstream,Java,Spring,Spring Mvc,Amazon S3,Inputstream,我有一个@Controller将图像返回到前端,但目前它在返回ResponseEntity对象之前将整个内容作为字节数组保存在内存中 我想改变这一点,这样它就可以流式输出图像,而不必首先将所有请求的图像保存在内存中 这些不是文件系统上的静态图像,而是存储在AmazonS3中的图像,我们正在考虑将来使用CloudFront,但现在我们必须充当中间人来检索文件 我发现了一个我在下面编写的示例,但是图像再次作为字节数组被读取并保存在内存中,因为write函数需要一个字节数组 有没有办法不用占用大量内存

我有一个
@Controller
将图像返回到前端,但目前它在返回
ResponseEntity
对象之前将整个内容作为字节数组保存在内存中

我想改变这一点,这样它就可以流式输出图像,而不必首先将所有请求的图像保存在内存中

这些不是文件系统上的静态图像,而是存储在AmazonS3中的图像,我们正在考虑将来使用CloudFront,但现在我们必须充当中间人来检索文件

我发现了一个我在下面编写的示例,但是图像再次作为字节数组被读取并保存在内存中,因为
write
函数需要一个字节数组

有没有办法不用占用大量内存就能做到这一点

这将在一个系统中使用,在这个系统中,客户端将打开一个充满图像的页面,每个页面都有多个分辨率,客户端非常快速地请求图像,因此后端必须在不使用所有内存资源的情况下提供图像

客户:

<img src="{root}/image/123/low/3" alt="Smiley face" height="42" width="42">

有一件事你是对的。永远不要将文件完全加载到内存中。文件大小可能超过总RAM容量(5 Gb、10 Gb),因此这不是处理文件的可靠方法。使用
IOUtils.toByteArray()
读取输入流并将其加载到单字节数组,这不是一件好事

你应该做的是一块一块地读,并在读完一块后再写。更像是流媒体。请参阅下面的代码更改。在这里,对于一个映像,在任何给定的时间内,将只使用8*2048字节或2 Kb的RAM。如果你想流得更快,你可以增加它

@RequestMapping(value = "/image/{id}/{quality}/{pageNumber}", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public void retrieveImage(@PathVariable Long id, @PathVariable String quality, @PathVariable Integer pageNumber,
        HttpServletResponse response) throws Exception{

    //Open connection
    S3Object s3Object = imageService.getS3Object(quality, pageNumber, id)
    S3ObjectInputStream s3ObjectIS = s3Object.getObjectContent();

    byte[] data = new byte[2048];
    int read = 0;
    OutputStream out = response.getOutputStream();
    while((read = s3ObjectIS.read(data)) > 0) {
        out.write(data, 0, read);
        out.flush();
    }
    out.close();

    //Then close connection to amazon......
}
可以通过AbstractPdfView的实现提供一些见解
@RequestMapping(value = "/image/{id}/{quality}/{pageNumber}", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public void retrieveImage(@PathVariable Long id, @PathVariable String quality, @PathVariable Integer pageNumber,
        HttpServletResponse response) throws Exception{

    //Open connection
    S3Object s3Object = imageService.getS3Object(quality, pageNumber, id)
    S3ObjectInputStream s3ObjectIS = s3Object.getObjectContent();

    response.getOutputStream().write(IOUtils.toByteArray(s3ObjectIS));

    //Then close connection to amazon......
}
@RequestMapping(value = "/image/{id}/{quality}/{pageNumber}", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public void retrieveImage(@PathVariable Long id, @PathVariable String quality, @PathVariable Integer pageNumber,
        HttpServletResponse response) throws Exception{

    //Open connection
    S3Object s3Object = imageService.getS3Object(quality, pageNumber, id)
    S3ObjectInputStream s3ObjectIS = s3Object.getObjectContent();

    byte[] data = new byte[2048];
    int read = 0;
    OutputStream out = response.getOutputStream();
    while((read = s3ObjectIS.read(data)) > 0) {
        out.write(data, 0, read);
        out.flush();
    }
    out.close();

    //Then close connection to amazon......
}