Écrire des données de fichier comme bzip2 à la sortie de la réponse de servlet
-
21-09-2019 - |
Question
Je suis en train d'obtenir Tomcat pour écrire le contenu de servlet en tant que fichier bzip2 (exigence peut-être idiot, mais il est apparemment nécessaire pour un travail d'intégration). J'utilise le framework Spring est donc ce dans un AbstractController.
J'utilise la bibliothèque bzip2 de http://www.kohsuke.org/bzip2/
Je peux obtenir le contenu BZippée bien, mais lorsque le fichier est écrit il semble contenir un tas de méta-données et est méconnaissable en tant que fichier bzip2.
Voici ce que je fais
// get the contents of my file as a byte array
byte[] fileData = file.getStoredFile();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//create a bzip2 output stream to the byte output and write the file data to it
CBZip2OutputStream bzip = null;
try {
bzip = new CBZip2OutputStream(baos);
bzip.write(fileData, 0, fileData.length);
bzip.close();
} catch (IOException ex) {
ex.printStackTrace();
}
byte[] bzippedOutput = baos.toByteArray();
System.out.println("bzipcompress_output:\t" + bzippedOutput.length);
//now write the byte output to the servlet output
//setting content disposition means the file is downloaded rather than displayed
int outputLength = bzippedOutput.length;
String fileName = file.getFileIdentifier();
response.setBufferSize(outputLength);
response.setContentLength(outputLength);
response.setContentType("application/x-bzip2");
response.setHeader("Content-Disposition",
"attachment; filename="+fileName+";)");
est appelée à partir de la méthode suivante au printemps AbstractController
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception
J'ai pris quelques coups à dans différentes approches, y compris l'écriture directement à la ServletOutput mais je suis assez perplexe et ne trouve pas beaucoup d'exemples / en ligne.
Tous les conseils de quelqu'un qui est venu dans ce avant serait très apprécié. bibliothèques / des approches alternatives sont très bien, mais malheureusement, il doit être bzip2.
La solution
L'approche affichée est en effet bizarre. Je l'ai réécrit pour qu'il est plus logique. Lui donner un essai.
String fileName = file.getFileIdentifier();
byte[] fileData = file.getStoredFile(); // BTW: Any chance to get this as InputStream? This is namely memory hogging.
response.setContentType("application/x-bzip2");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
OutputStream output = null;
try {
output = new CBZip2OutputStream(response.getOutputStream());
output.write(fileData);
} finally {
output.close();
}
Vous voyez, juste envelopper le flux de sortie de la réponse avec CBZip2OutputStream
et écrire le byte[]
lui.
Vous pouvez arriver à voir IllegalStateException: Response already committed
venir après dans les journaux de serveur (avec le téléchargement étant correctement envoyé par la voie), cela signifie que le printemps tente de transmettre la demande / réponse par la suite. Je ne fais pas du printemps, donc je ne peux pas aller en détail, mais vous devriez au moins demander Spring rester à l'écart de la réponse. Ne le laissez pas faire une correspondance, vers l'avant ou peu importe. Je pense que le retour null
suffit.
Autres conseils
Vous trouverez peut-être travailler avec CompressorStreamFactory de commons-compress un peu plus facile. Il est une personne décédée de la version Ant vous travaillez déjà avec et finit par 2 lignes différentes de l'exemple de BalusC.
Plus ou moins une question de préférence bibliothèque.
OutputStream out = null;
try {
out = new CompressorStreamFactory().createCompressorOutputStream("bzip2", response.getOutputStream());
IOUtils.copy(new FileInputStream(input), out); // assuming you have access to a File.
} finally {
out.close();
}