Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/400.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Spring Boot中不保留内存而流式传输/下载文件_Java_Spring_Spring Boot_Google Cloud Storage - Fatal编程技术网

Java 在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

我的应用程序使用Google云存储来存储大文件,并使用Spring Boot作为后端

我刚刚完成了负责下载的控制器的实现,遵循我认为可能是正确的方法,但是我从浏览器中得到的行为并不是我所期望的

步骤

如果我尝试下载文件,将发生以下情况:

  • 该文件(“blob”)是使用ReadChannel从google云存储中读取的
  • 通道写入ByteArrayOutputStream
  • 通道使用缓冲区写入
  • ByteArrayOutputStream在InputStreamResource中转换
  • 然后将inputStream资源传入ResponseEntity
  • 意外行为

    如果用户转到下载控制器并请求特定文件,则该文件首先完全加载到服务器上,然后提供给客户端。同时,客户端认为服务器“没有响应”(因为服务器正在加载文件),这是不好的。当文件完全加载到服务器上时,会很快出现在“下载”中

    我想要的是避免出现“无响应”部分,将文件或流式传输到客户端,就像在尝试下载大文件时通常发生的情况一样,在Chrome中文件周围会出现“下载”轮

    如果您能帮助理解以下代码的错误,我们将不胜感激

    Sring控制器的代码如下所示:

    @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
    ,而不是你自己的输出流。讨厌我的生活!谢谢你,成功了!