java - 从 Spring MVC 端点流式传输动态图像而不将其保存在内存中

标签 java spring spring-mvc amazon-s3 inputstream

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

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

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

我找到了一个我在下面编码的示例,但是再次读取图像并将其作为内存中的字节数组保存为 write函数需要一个字节数组。

有什么办法可以不占用大量内存吗?

这将用于一个系统,在该系统中,客户端将打开一个充满图像的页面,每个图像都有多个级别的分辨率,客户端请求图像的速度非常快,因此后端必须提供图像而无需使用所有内存资源。

客户:

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

后端我现在拥有的:

@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{
byte[] imageBytes = getImageFromS3(id, quality, pageNumber);
return new ResponseEntity<byte[]>(imageBytes, createCachingStrategy(), HttpStatus.OK);

}

我在网上找到的东西:

@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......
}

最佳答案

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

你应该做的是一个 block 一个 block 地读,读完一个 block 就写。更像是流媒体。请参阅下面的代码更改。这里对于图像的任何给定时间将仅使用 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......
}

关于java - 从 Spring MVC 端点流式传输动态图像而不将其保存在内存中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34193470/

相关文章:

java - 用于 Java 的 NHibernate MultiQuery

java - 错误的存储库 - Maven

java - 具有变量 JsonProperty 的 Jackson 泛型(与泛型一起使用)

java - RESTful 服务的 url 设计

java - 如何在Java中使用Redis命令 “bitcount”

java - 重定向到 spring security 预认证中的错误页面

spring - 在@Component类中注册bean是否尊重@Scope?

spring - 如何在spring boot中查看schema sql(DDL)?

java - Apache Camel bean 参数与 Spring DSL 的绑定(bind)问题

spring - SpringCharacterEncodingFilter的目的是什么