Java 在Spring Boot中不保留内存而流式传输/下载文件
我的应用程序使用Google云存储来存储大文件,并使用Spring Boot作为后端 我刚刚完成了负责下载的控制器的实现,遵循我认为可能是正确的方法,但是我从浏览器中得到的行为并不是我所期望的 步骤 如果我尝试下载文件,将发生以下情况:Java 在Spring Boot中不保留内存而流式传输/下载文件,java,spring,spring-boot,google-cloud-storage,Java,Spring,Spring Boot,Google Cloud Storage,我的应用程序使用Google云存储来存储大文件,并使用Spring Boot作为后端 我刚刚完成了负责下载的控制器的实现,遵循我认为可能是正确的方法,但是我从浏览器中得到的行为并不是我所期望的 步骤 如果我尝试下载文件,将发生以下情况: 该文件(“blob”)是使用ReadChannel从google云存储中读取的 通道写入ByteArrayOutputStream 通道使用缓冲区写入 ByteArrayOutputStream在InputStreamResource中转换 然后将inputSt
@RequestMapping("/**/*")
public ResponseEntity<InputStreamResource> downloadFile(
RedirectAttributes redirectAttributes, HttpServletRequest request, HttpServletResponse response) throws Exception {
String fid = ....
WritableByteChannel channel;
Storage storage = new DownloadAction().getStorage();
BlobId blobId = BlobId.of(BUCKET_ID, blobPath);
Blob blob = storage.get(blobId);
ByteArrayOutputStream writeTo = new ByteArrayOutputStream();
try (ReadChannel reader = blob.reader()) {
channel = Channels.newChannel(writeTo);
ByteBuffer bytes = ByteBuffer.allocate(64 * 1024);
while (reader.read(bytes) > 0) {
bytes.flip();
channel.write(bytes);
bytes.clear();
}
}
channel.close();
writeTo.close();
InputStream tmp = new ByteArrayInputStream(writeTo.toByteArray());
InputStreamResource resource = new InputStreamResource(tmp);
MediaType mediaType = MediaType.parseMediaType(mimeType);
return ResponseEntity.ok()
.contentType(mediaType)
.contentLength(fileSize)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.body(resource);
} catch (IOException e) {
return ResponseEntity.notFound().build();
}
} catch (Exception e) {
return ResponseEntity.notFound().build();
}
}
@RequestMapping(“/****”)
公共响应下载文件(
RedirectAttributes RedirectAttributes、HttpServletRequest请求、HttpServletResponse响应)引发异常{
字符串fid=。。。。
可由Techannel通道写入;
Storage Storage=new DownloadAction().getStorage();
BlobId BlobId=BlobId.of(BUCKET\u ID,blobPath);
Blob Blob=storage.get(blobId);
ByteArrayOutputStream writeTo=新建ByteArrayOutputStream();
try(ReadChannel reader=blob.reader()){
channel=Channels.newChannel(writeTo);
ByteBuffer字节=ByteBuffer.allocate(64*1024);
while(reader.read(字节)>0){
flip();
信道写入(字节);
clear();
}
}
channel.close();
writeTo.close();
InputStream tmp=新的ByteArrayInputStream(writeTo.toByteArray());
InputStreamResource资源=新的InputStreamResource(tmp);
MediaType MediaType=MediaType.parseMediaType(mimeType);
返回ResponseEntity.ok()
.contentType(mediaType)
.contentLength(文件大小)
.header(HttpHeaders.CONTENT\u处置,“附件;文件名=\”+文件名+“\”)
.机构(资源);
}捕获(IOE异常){
返回ResponseEntity.notFound().build();
}
}捕获(例外e){
返回ResponseEntity.notFound().build();
}
}
根据您的问题,您存储桶中的对象是私有的,您希望为有限的人群提供访问权限。
如果是的话,你需要的就是签名的URL
您可以为bucket中的特定对象生成签名URL,并将用户重定向到生成的URL,这样他就可以自己下载文件
更多信息:我希望他们总是通过服务器进行下载,并将服务器用作希望下载文件的用户和存储设备之间的“中间件”。我不想让他们自己下载文件,实际上,我想对用户完全隐藏存储空间。所以,这就是签名URL的用途。您可以生成特定用户可用的签名URL。因此,该用户只能下载特定对象(文件)-例如,他无法浏览您的Butchet。签名URL也有一个时间限制,在一段时间后,由您指定-URL变得不可用(无效)。很明显,您是先将其读入内存的,为什么。。直接流到响应的
OutputStream
,而不是你自己的输出流。讨厌我的生活!谢谢你,成功了!