I am working on a Java1.7 Struts1 application.
It can successfully download a file by doing the following:
response.setContentType("text/html");
response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
BufferedOutputStream fos = null;
try {
OutputStream output = response.getOutputStream();
fos = new BufferedOutputStream(output);
fos.write(bytes);
fos.flush();
fos.close();
} catch (IOException e) {
logger.error("Error trying to download the BAS file. "+e.getMessage());
}
However, when when it does this, it changes the HttpServletResponse object. This means that when the Action class performs the following:
return mapping.findForward(forwards.success.toString());
It does not forward to that location (it just stays on the current page, i.e. does the download and nothing else).
If it does not do the download, i.e. does not change the HttpServletResponse object, then it does the forward successfully.
Question
How can I make it download the file (i.e. write to the HttpServletResponse, and then do the forward succesfully?
Related
I have a web page which links to an Excel 2007 worksheet. It is a upload details in .xlsx file and download in .csv file. When I click on the download link and trying to open i get the usual dialog box to either open/save the Excel file. On clicking 'Open', I get the following warning message-
The file you are trying to open, 'filename.csv' is in a different format than specified by the file extension. Verify that the file is not corrupted and is from a trusted source before opening the file. Do you want to open the file now?
I developed this code in Java
private void downloadExcelSheet(HSSFWorkbook workbook, String sheetName){
OutputStream out = null;
try{
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
workbook.write(outByteStream);
byte[] bytes = outByteStream.toByteArray(); //workbook.getBytes()
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.reset();
String disHeader = "Attachment;Filename=\""+sheetName+".csv\"";
response.addHeader("Content-Disposition", disHeader);
response.setContentType("text/csv");
//response.setHeader("Content-Disposition", "attachment; filename=\""+sheetName+".csv");
//response.setContentType("text/csv");
response.setContentLength(bytes.length);
out = response.getOutputStream();
out.write(bytes);
out.flush();
}catch(IOException ioe){
ioe.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
if(out!=null){
out.close();
}
}catch(IOException io){
io.printStackTrace();
}
}
}
I am trying to add a function to my web app which lets the users download an excel file.
I'm trying to achieve this with the following code:
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
File file = new File("d:/test/test.xls");
response.setContentType("application/xls");
response.addHeader("Content-Disposition", "attachment; filename=test.xls");
response.setContentLength((int) file.length());
try {
FileInputStream fileInputStream = new FileInputStream(file);
OutputStream responseOutputStream = response.getOutputStream();
int bytes;
while ((bytes = fileInputStream.read()) != -1) {
responseOutputStream.write(bytes);
}
fileInputStream.close();
responseOutputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I'm able to download the excel file with the above code, however the file is corrupted. If I open it with microsoft excel, I get a popup with the message:
"the file format and extension of don't match. the file could be corrupted or unsafe".
And the excel file is empty.
After running the code, the original file(d:/test/test.xls) gets also corrupted.
What am I doing wrong?
The official MIME type for Excel file .xls is application/vnd.ms-excel and for .xlsx is application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.
Also, I would suggest doing response.reset() prior to writing to the output stream and responseOutputStream.flush() (important) prior to closing the response.
Try below code :
File file = null;
InputStream in = null;
OutputStream outstream = null;
try {
response.reset();
in = new FileInputStream(file);
response.setContentType("application/vnd.ms-excel");
response.addHeader("content-disposition", "attachment; filename=data.xls");
outstream = response.getOutputStream();
IOUtils.copyLarge(in, outstream);
}
catch (Exception e) {
out.write("Unable to download file");
}finally {
IOUtils.closeQuietly(outstream);
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
if (file != null)
file.delete();
}
dont forgot to add apache commons-io-2.4 in your dependency
I have the below code got from mkyong, to zip files on local. But, my requirement is to zip files on server and need to download that. Could any one help.
code wrote to zipFiles:
public void zipFiles(File contentFile, File navFile)
{
byte[] buffer = new byte[1024];
try{
// i dont have idea on what to give here in fileoutputstream
FileOutputStream fos = new FileOutputStream("C:\\MyFile.zip");
ZipOutputStream zos = new ZipOutputStream(fos);
ZipEntry ze= new ZipEntry(contentFile.toString());
zos.putNextEntry(ze);
FileInputStream in = new FileInputStream(contentFile.toString());
int len;
while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
in.close();
zos.closeEntry();
//remember close it
zos.close();
System.out.println("Done");
}catch(IOException ex){
ex.printStackTrace();
}
}
what could i provide in fileoutputstream here? contentfile and navigationfile are files i created from code.
If your server is a servlet container, just write an HttpServlet which does the zipping and serving the file.
You can pass the output stream of the servlet response to the constructor of ZipOutputStream and the zip file will be sent as the servlet response:
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
Don't forget to set the response mime type before zipping, e.g.:
response.setContentType("application/zip");
The whole picture:
public class DownloadServlet extends HttpServlet {
#Override
public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=data.zip");
// You might also wanna disable caching the response
// here by setting other headers...
try ( ZipOutputStream zos = new ZipOutputStream(response.getOutputStream()) ) {
// Add zip entries you want to include in the zip file
}
}
}
Try this:
#RequestMapping(value="download", method=RequestMethod.GET)
public void getDownload(HttpServletResponse response) {
// Get your file stream from wherever.
InputStream myStream = someClass.returnFile();
// Set the content type and attachment header.
response.addHeader("Content-disposition", "attachment;filename=myfilename.txt");
response.setContentType("txt/plain");
// Copy the stream to the response's output stream.
IOUtils.copy(myStream, response.getOutputStream());
response.flushBuffer();
}
Reference
i have implemented a servlet to download doc files available under my application classpath.
what happening is; file is downloading but ms-word is unable to open it property.
see the screenshot of ms-word:
Servlet implementation is as follows:
public class DownloadFileServlet extends HttpServlet {
protected void doGet(
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String fileName = "test.doc";
ClassPathResource resource = new ClassPathResource(File.separator + fileName);
ServletOutputStream sos = null;
FileInputStream fis = null;
try {
response.setContentType("application/msword");
response.setHeader("Content-disposition", "attachment; fileName=\"" + fileName + "\"" );
fis = new FileInputStream(new File(resource.getURI().getPath()));
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(fis);
sos = response.getOutputStream();
sos.write(bytes);
sos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if( fis != null) {
fis.close();
}
if( sos != null) {
sos.close();
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
i have tried almost all suggested Content Types for ms-word files. but still it is not working.
application/msword
application/ms-word
application/vnd.ms-word
Kindly suggest I'm making a mistake or is there any other way to achieve.
Note: i have tried almost all approaches available on SO.
Instead of reading, converting to byte[] simply write directly to the OutputStream. You shouldn't close the OutputStream as that is being handled by the container for you.
I would rewrite your servlet method to more or less the following (also why is it a servlet and not a (#)Controller?
protected void doGet(
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String fileName = "test.doc";
ClassPathResource resource = new ClassPathResource(File.separator + fileName);
InputStream input = resource.getInputStream();
try {
response.setContentType("application/msword");
response.setHeader("Content-disposition", "attachment; fileName=\"" + fileName + "\"" );
org.springframework.util.StreamUtils.copy(input, response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOEXception ie) {}
}
}
}
i do not know what a ClassPathResource class does. hence modified the code a bit.
ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
InputStream is = clsLoader.getResourceAsStream("test.doc");
and in the try block use:
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(is);
this should work fine. i placed the doc in the classpath. modify it to suit your needs.
Regarding the mime mapping, open your server properties and you will find a list of mime mapping. Eg. in eclipse for tomcat, just double click on the server and you should be able to find the mime mapping list there. application/msword worked fine
I am tryig to make a song available for download on my website. I am using a download servlet that I have used before to make zip files available for download. I have run through the code and everything appears to be working, the output stream reads the entire file but the save dialog box does not appear. Any ideas? Thanks for your help. Code is as follows:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String song = request.getParameter("song");
StringBuilder filePath = new StringBuilder();
try {
Thread.sleep(1);
String[] info = getSongInfo(song);
filePath.append("D:\\My Music\\My Song.m4a");
File file = new File(filePath.toString());
if (!file.exists()) {
throw new FileNotFoundException(file.getAbsolutePath());
}
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Type", "audio/mp4a-latm");
response.setHeader("Content-disposition", "attachment; filename="+song+".m4a");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
byte[] buf = new byte[4096];
while (true) {
int length = bis.read(buf);
if (length == -1) {
break;
}
bos.write(buf, 0, length);
}
bos.flush();
bos.close();
bis.close();
} catch (InterruptedException e) {
System.err.println("Error message: " + e.getMessage());
}
}
Called using:
dojo.xhrGet(
{
url: "/downloadSong?song="+item.title[0]
});
You cannot download files by ajax. JavaScript has due to security reasons no facility to spawn a Save As dialogue nor to store them in disk. It will consume the response, but it can't do anything sensible with it.
You need to use window.location instead:
window.location = "/downloadSong?song=" + item.title[0];
Thanks to the Content-Disposition: attachment header, it won't affect the currently opened page.