2010-02-19 7 views
1

Я пытаюсь заставить Tomcat выписать содержимое сервлета в виде файла bzip2 (возможно, необходимо глупое требование, но это, по-видимому, необходимо для некоторой работы по интеграции). Я использую фреймворк Spring, так что это в AbstractController.Запишите данные файла как Bzip2 для вывода ответа сервлета

Я использую библиотеку bzip2 из http://www.kohsuke.org/bzip2/

я могу получить содержимое сжатые bzip'ом хорошо, но когда файл записывается, кажется, содержит кучу мета-данных и неузнаваем в виде файла bzip2.

Вот что я делаю

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

Это вызывается из следующего метода весной AbstractController

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception 

Я взял несколько уколов на него в различных подходах, в том числе пишу непосредственно на ServletOutput, но я довольно тупик и не могу найти ни одного/много примеров в Интернете.

Любые советы любого, кто сталкивался с этим ранее, будут высоко оценены. Альтернативные библиотеки/подходы прекрасны, но, к сожалению, это должно быть bzip2'd.

ответ

3

Опубликованный подход действительно странный. Я переписал так, что это имеет смысл. Попробуйте.

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(); 
} 

Вы видите, просто обернуть выходной поток ответа с CBZip2OutputStream и написать byte[] к нему.

Возможно, вам придет после этого IllegalStateException: Response already committed в журналах сервера (при правильной отправке загрузки, кстати), то это означает, что Spring пытается перенаправить запрос/ответ после этого. Я не делаю весну, поэтому не могу подробно остановиться, но вы должны хотя бы проинструктировать Весну держаться подальше от ответа. Не позволяйте ему делать сопоставление, пересылать или что-то еще. Я думаю, что возвращения null хватает.

+0

+1 для раннего предупреждения о возможном исключении IllegalStateException. –

2

Возможно, вы найдете работу с CompressorStreamFactory от commons-compress немного проще. Это отработанная версия Ant, с которой вы уже работаете, и заканчивается двумя строками, отличными от примера BalusC.

Более или менее вопрос библиотеки.

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(); 
}