从具有输出流的弹簧@Controller返回文件编辑编辑 2

2022-09-01 21:33:12

我想从Spring控制器返回文件。我已经有API可以给我任何TransputStream的实现,然后我需要将其发送给用户。

所以流程是这样的:

获取输出流 -> 服务将此输出流传递给控制器 ->控制器必须将其发送给用户

我认为我需要输入流来做到这一点,我还发现了Apache Commons api功能,如下所示:

IOUtils.copy(InputStream is, OutputStream os)

但问题是,它将其转换为另一侧 - >不是从osis,而是从isos

编辑

需要明确的是,因为我看到答案没有正确:
我使用Dropbox api并在OutputStream中接收文件,我希望在输入某些URL时将此输出流发送给用户

FileOutputStream outputStream = new FileOutputStream(); //can be any instance of OutputStream
DbxEntry.File downloadedFile = client.getFile("/fileName.mp3", null, outputStream);

这就是为什么我谈论将输出流转换为输入流,但不知道如何做到这一点。此外,我认为有更好的方法来解决这个问题(也许从输出流中以某种方式返回字节数组)

我试图通过参数将servlet outputstream [response.getOutputstream()]传递给从Dropbox下载文件的方法,但它根本不起作用

编辑 2

我的应用程序的“流”是这样的:@Joeblade

  1. 用户输入网址:/download/{file_name}

  2. Spring Controller捕获url并调用@Service层以下载文件并将其传递给该控制器:

    @RequestMapping(value = "download/{name}", method = RequestMethod.GET)
    public void getFileByName(@PathVariable("name") final String name, HttpServletResponse response) throws IOException {
        response.setContentType("audio/mpeg3");
        response.setHeader("Content-Disposition", "attachment; filename=" + name);
        service.callSomeMethodAndRecieveDownloadedFileInSomeForm(name); // <- and this file(InputStream/OutputStream/byte[] array/File object/MultipartFile I dont really know..) has to be sent to the user
    }
    
  3. 现在,@Service调用 Dropbox API 并按指定的file_name下载文件,并将其全部放入 OutputStream,然后将其(以某种形式..可能是 OutputStream、byte[] 数组或任何其他对象 - 我不知道哪个更好使用)传递给控制器:

    public SomeObjectThatContainsFileForExamplePipedInputStream callSomeMethodAndRecieveDownloadedFileInSomeForm(final String name) throws IOException {
        //here any instance of OutputStream - it needs to be passed to client.getFile lower (for now it is PipedOutputStream)
        PipedInputStream inputStream = new PipedInputStream(); // for now
        PipedOutputStream outputStream = new PipedOutputStream(inputStream);
    
    
        //some dropbox client object
        DbxClient client = new DbxClient();
        try {
            //important part - Dropbox API downloads the file from Dropbox servers to the outputstream object passed as the third parameter
            client.getFile("/" + name, null, outputStream);
        } catch (DbxException e){
            e.printStackTrace();
        } finally {
            outputStream.close();
        }
        return inputStream;
    }
    
  4. 控制器接收文件(我完全不知道,正如我上面所说的那样,以哪种形式),然后将其传递给用户

所以事情是通过调用方法接收下载的文件,然后这个包含下载的文件,必须发送给用户,如何做到这一点?OutputStreamdropboxClient.getFile()OutputStream


答案 1

从HttpServletResponse获取输出流并将文件写入其中(在本例中使用Apache Commons中的IOUtils)

@RequestMapping(value = "/download", method = RequestMethod.GET)
public void download(HttpServletResponse response) {
    ...
    InputStream inputStream = new FileInputStream(new File(PATH_TO_FILE)); //load the file
    IOUtils.copy(inputStream, response.getOutputStream());
    response.flushBuffer();
    ...
}

确保使用 try/catch 在发生异常时关闭流。


答案 2

最可取的解决方案是将 InputStreamResource 与 结合使用。您只需手动设置:ResponseEntityContent-Length

@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity download() throws IOException {
    String filePath = "PATH_HERE";
    InputStream inputStream = new FileInputStream(new File(filePath));
    InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
    HttpHeaders headers = new HttpHeaders();
    headers.setContentLength(Files.size(Paths.get(filePath)));
    return new ResponseEntity(inputStreamResource, headers, HttpStatus.OK);
}