2010-02-19 13 views
1

J'essaye d'obtenir que Tomcat écrive le contenu du servlet en tant que fichier bzip2 (exigence idiote peut-être mais c'est apparemment nécessaire pour un travail d'intégration). J'utilise le framework Spring, donc c'est dans un AbstractController.Écrire les données du fichier en tant que Bzip2 à la sortie de la réponse de servlet

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+";)"); 

On appelle cela 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 J'écris directement sur le ServletOutput mais je suis assez perplexe et je ne trouve aucun/plusieurs exemples en ligne.

Tous les conseils de toute personne rencontrée auparavant seraient grandement appréciés. Les bibliothèques alternatives/approches sont bien, mais malheureusement, il doit être bzip2'd.

Répondre

3

L'approche affichée est en effet étrange. J'ai réécrit pour que cela ait plus de sens. Essaie.

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.

Il se peut que vous voyiez IllegalStateException: Response already committed dans les journaux du serveur (le téléchargement étant correctement envoyé), cela signifie que Spring tente de transmettre la demande/réponse par la suite. Je ne fais pas le printemps, donc je ne peux pas aller en détail, mais vous devriez au moins instruire le printemps rester à l'écart de la réponse. Ne le laissez pas faire une cartographie, en avant ou quoi que ce soit. Je pense que le retour null suffit.

+0

+1 pour l'avertissement précoce d'une éventuelle exception IllegalStateException. –

2

Vous pourriez trouver de travailler avec CompressorStreamFactory de commons-compress un peu plus facile. C'est une version décimée de la version Ant avec laquelle vous travaillez déjà et qui se termine par 2 lignes différentes de l'exemple de BalusC.

Plus ou moins une question de préférence de 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(); 
}