azalut azalut - 4 months ago 9x
Java Question

Return file from Spring @Controller having OutputStream

I want to return a file from a Spring controller. I already have API that can give me any implementation of OutputStream and then I need to send it to a user.

So the flow is something like that:

getting outputstream -> service passes this outputstream to controller -> controller has to send it to a user

I think I need inputstream to do it and I have also found Apache Commons api feature that looks like this:

IOUtils.copy(InputStream is, OutputStream os)

but the problem is, it converts it to the other side -> not from os to is, but from is to os.


to be clear, because I see the answers are not hitting right thing:

I use Dropbox api and recieve file in OutputStream and I want this output stream to be sent to user while entering some URL

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

Thats why i was talking about converting outputstream to inputstream, but have no idea how to do it. Furthermore, I suppose that there is better way to solve this (maybe return byte array somehow from outputstream)

I was trying to pass servlet outputstream [response.getOutputstream()] through parameter to the method that downloads file from dropbox, but it didnt work, at all

Edit 2

(I cant paste the code in an elegant form, dont know why, so I will paste links with code)

The "flow" of my app is something like this: @Joeblade

  1. User enters url: /download/{file_name}

  2. Spring Controller captures the url and calls the @Service layer to download the file and pass it to that controller:

  3. Now the @Service calls Dropbox API and downloads the file by specified file_name, and puts it all to the OutputStream, and then passes it (in some form.. maybe OutputStream, byte[] array or any other object - I dont know which is better to use) to the controller:

  4. Controler recieves the file (I dont know, at all, in which form as I said upper) and passes it then to the user

So the thing is to recieve OutputStream with the downloaded file by calling dropboxClient.getFile() method and then this OutputStream that contains the downloaded file, has to be sent to the user, how to do this?


You could use the ByteArrayOutputStream and ByteArrayInputStream. Example:

// A ByteArrayOutputStream holds the content in memory
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

// Do stuff with your OutputStream

// To convert it to a byte[] - simply use
final byte[] bytes = outputStream.toByteArray();

// To convert bytes to an InputStream, use a ByteArrayInputStream
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);

You can do the same with other stream pairs. E.g. the file streams:

// Create a FileOutputStream
FileOutputStream fos = new FileOutputStream("filename.txt");

// Write contents to file

// Always close the stream, preferably in a try-with-resources block

// The, convert the file contents to an input stream
final InputStream fileInputStream = new FileInputStream("filename.txt");

And, when using Spring MVC you can definitely return a byte[] that contains your file. Just make sure that you annotate your response with @ResponseBody. Something like this:

public byte[] serveFile(@PathVariable("file"} String file) throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
    DbxEntry.File downloadedFile = client.getFile("/" + filename, null, outputStream);
    return outputStream.toByteArray();