De retour de fichier à partir du Printemps @Contrôleur OutputStream
Je souhaite retourner un fichier à partir d'un Printemps contrôleur. J'ai déjà API qui peut me donner toute la mise en œuvre de OutputStream et puis j'ai besoin de l'envoyer à un utilisateur.
De sorte que le flux est quelque chose comme ça:
arriver outputstream -> service passe cette outputstream de contrôleur de -> contrôleur a pour l'envoyer à un utilisateur
Je pense que j'ai besoin d'inputstream de le faire et j'ai aussi trouvé de Apache Commons api fonctionnalité qui ressemble à ceci:
IOUtils.copy(InputStream is, OutputStream os)
mais le problème est, il convertit l'autre côté -> pas de os à est, mais à partir de est à os.
Modifier
pour être clair, parce que je vois les réponses ne sont pas les coups chose:
J'utilise Dropbox api et de recevoir des fichiers dans OutputStream et je veux que ce flux de sortie pour être envoyé à l'utilisateur lors de la saisie d'une URL
FileOutputStream outputStream = new FileOutputStream(); //can be any instance of OutputStream
DbxEntry.File downloadedFile = client.getFile("/fileName.mp3", null, outputStream);
C'est pourquoi je parlais de conversion outputstream à inputstream, mais n'ont aucune idée de comment le faire. En outre, je suppose qu'il y a une meilleure façon de résoudre ce problème (peut-être revenir tableau d'octets en quelque sorte de outputstream)
J'essayais de passer servlet outputstream [réponse.getOutputstream()] paramètre à la méthode qui télécharge un fichier à partir de dropbox, mais il ne fonctionne pas, à tous les
Edit 2
Le "flux" de mon application est quelque chose comme ceci: @Joeblade
- Utilisateur saisit url: /download/{nom_fichier}
- Printemps Contrôleur de capture de l'url et des appels la @couche de Service pour télécharger le fichier et de le transmettre à qui de contrôleur:
@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 }
- Maintenant l' @appels de Service Dropbox API et télécharge le fichier spécifié par file_name, et met tout à la OutputStream, et passe ensuite (dans une certaine forme.. peut-être OutputStream, byte[] tableau ou tout autre objet - je ne sais pas ce qui est mieux pour l'utilisation) du contrôleur:
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; }
- Contrôleur reçoit le fichier (je ne sais pas, à tous, qui, par la forme comme je l'ai dit en haut) et le transmet ensuite à l'utilisateur
Le truc c'est de recevoir OutputStream
avec le fichier téléchargé en appelant dropboxClient.getFile()
méthode, puis ce OutputStream
qui contient le fichier téléchargé, doit être envoyé à l'utilisateur, comment faire?
OriginalL'auteur azalut | 2015-01-02
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser le
ByteArrayOutputStream
etByteArrayInputStream
. Exemple:Vous pouvez faire de même avec d'autres flux de paires. E. g. le flux de fichier:
Et, lors de l'utilisation de Spring MVC, vous pouvez certainement revenir un
byte[]
qui contient votre fichier. Assurez-vous de les annoter votre réponse avec@ResponseBody
. Quelque chose comme ceci:Eh bien, le problème avec l'Octet de flux, c'est que vous garder tout en mémoire. Si le fichier est gros, il signifie aussi que vous devez garder beaucoup d'octets en mémoire. La meilleure approche serait probablement passer la
response.getOutputStream()
directement. Pourquoi ne pas travailler pour vous?Je ne connais, quand je retourne void de contrôleur et enregistrez le fichier de réponse.getOutputStream (), puis rien ne se passe lorsque j'entre l'URL, mais quand je retourne byte[] de contrôleur et d'ajouter des en-têtes de la réponse, tout est droit, Et aussi la question: comment faire pour vérifier si le fichier n'est pas vide? (lorsque pass nom de fichier, qui n'existent pas dans Dropbox, puis je suis pas certains vides réponse appropriée pour l'exemple de code 404, mais fichier vide et 200 OK)
OriginalL'auteur wassgren
Obtenir le OutputStream de la HttpServletResponse et écrire le fichier (dans cet exemple à l'aide de IOUtils de Apache Commons)
Assurez-vous d'utiliser un try/catch pour la fermeture du flux dans le cas d'une exception.
Smith, je suis en train de télécharger fichier audio (.wav) de votre solution fonctionne très bien sur ma machine de développement (OS Windows) mais quand je le déployer sur le Serveur Ubuntu, Il retourne seulement 200 octets que les résultats dans le fichier corrompu qui n'est pas jouable... une idée de quoi de mal avec l'exécution de la solution sur ubuntu??
OriginalL'auteur John Smith
Le plus préférable solution est d'utiliser InputStreamResource avec
ResponseEntity
. Tous vous avez besoin estContent-Length
manuellement:Flux est enveloppé dans HttpServletResponse, de sorte que le récepteur doit la fermer. Je pense que conteneur de Servlet doit gérer cela sous le capot.
HttpHeaders
ne sont pas nécessaires. Vous pouvez écrirereturn ResponseEntity.ok().contentLength(Files.size(Paths.get(filePath)).body(inputStreamResource)
OriginalL'auteur Konstantin Konyshev
Je recommande la lecture de cette réponse
répondu par michal.kreuzman
J'allais écrire quelque chose de semblable à moi mais bien sûr qu'il a déjà été répondu.
Si vous voulez juste passer le flux à la place de premier de tout dans la mémoire vous pouvez utiliser cette réponse
Je n'ai pas testé (pas au travail), mais il semble légitime 🙂
La chose est, c'est à peu près le même que IOUtils.copie /IOUtils.copyLarge. ligne: 2128
Qui vous disent que des copies de la mauvaise direction.
Cependant tout d'abord assurez-vous de comprendre ce que vous demandez. Si vous voulez lire un outputstream(objet de l'écriture) et les écrire dans un flux d'entrée (objet à lire à partir de) alors je pense que ce que vous voulez vraiment est d'écrire à un objet qui fournit également une option de lecture.
pour que vous pourriez utiliser un PipedInputStream et PipedOutputStream. Ceux-ci sont connectés ensemble afin d'octets écrits dans le outputstream sont disponibles pour être lu à partir de la correspondante du flux d'entrée.
donc à l'endroit où vous recevez les octets je suppose que vous êtes l'écriture d'octets à un outputstream.
il y a cela:
Si vous utilisez IOUtils.copie il continue à lire jusqu'à ce que le outputstream est fermé. donc, assurez-vous qu'il est déjà fermé avant de commencer (si vous lancez la lecture/écriture sur le même thread) ou utiliser un autre thread pour écrire dans la mémoire tampon de sortie et de le fermer à la fin.
Si ce n'est pas ce que vous cherchez, alors vous aurez à affiner votre question.
si cela ne vous aide pas, puis je ne suis pas sûr de comprendre la question 😀
apperciate votre mise à jour 🙂 j'ai essayé votre réponse et il est bon, mais pas encore parfait; quand je rentre l'URL qui m'envoie le fichier, puis je le recevoir, mais il est vide et n'a pas d'extension. Après j'ai télécharger le fichier à partir de dropbox, je veux que le fichier soit envoyé à l'utilisateur, en quelque sorte; je mettrai à jour mon post pour un moment, et alors, peut-être que vous pourriez m'aider 🙂
j'ai trouvé le problème; quand je tape dans l'url: nom.extension, seul le nom est enregistré pour @PathVariable et l'extension n'est pas, donc j'ai dû utiliser certains reg-exp corresponde et maintenant fonctionne très bien 🙂 même si j'ai encore besoin de vérifier quelque part, si mon dossier n'est pas vide
OriginalL'auteur Joeblade
Une chose à garder à l'esprit lors de l'écriture de la réponse outputstream, c'est que c'est une très bonne idée d'appeler la méthode flush() sur n'importe quel écrivain que vous avez enveloppé avec régulièrement. La raison pour cela est que d'une connexion interrompue (par exemple causée par un utilisateur de l'annulation d'un téléchargement) ne finissent pas lancer une exception pour une longue période de temps, si jamais. Cela peut effectivement être une fuite de ressources sur votre récipient.
OriginalL'auteur seismic
Le plus efficace de la mémoire de la solution dans votre cas, serait de passer la réponse
OutputStream
droit à l'API Dropbox:Les données lues par l'API sera envoyé directement à l'utilisateur. Aucune autre octets de la mémoire tampon n'est requise.
Comme pour
PipedInputStream
/PipedOutputStream
, ils sont conçus pour le blocage de la communication entre les 2 threads.PipedOutputStream
blocs thread d'écriture après 1024 octets (par défaut) jusqu'à ce qu'un autre thread commencer la lecture à partir de la fin de la pipe (PipedInputStream
).OriginalL'auteur Lu55