我有一个 @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/