Issue opening Excel documents with Internet Explorer - java

I have run into an issue in which IE does not open up the Save As/Open dialog box for an Excel document like Firefox does.
So I have created a servlet filter that is using '*.xls' as the url pattern. The issue that I now face (since this is the first filter I have created) is how to get the name of the file that the user wants so that the dialog box gets populated correctly. Currently the filter is invoked when the user selects a link on a given page.
Here is what I came up with:
The above is what I have doFilter().
String fileName = "fileName.xls";
HttpServletRequest httpRequest = (HttpServletRequest) pRequest;
String requestURI = httpRequest.getRequestURI();
if(StringUtils.isNotBlank(requestURI))
{
String uri[] = StringUtils.split(requestURI, '/');
fileName = uri[uri.length - 1];
}
HttpServletResponse httpResponse = (HttpServletResponse) pResponse;
httpResponse.setContentType("application/vnd.ms-excel");
httpResponse.setHeader("Content-disposition", "attachment; filename=\"" + fileName +"\"");
web.xml:
<filter>
<filter-name>ExcelFilter</filter-name>
<filter-class>vsg.rp.common.ExcelFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ExcelFilter</filter-name>
<url-pattern>*.xls</url-pattern>
</filter-mapping>
This all is working on my development box: Windows XP, JBoss, Eclipse, Oracle. But when it runs on the test server—Linux, Apache/JBoss, Oracle—it does not work. It appears that the filter is not even being called, no errors thrown, etc. Any idea as to why this would happen?

You want the content type set appropriately as well as the content disposition header, thus:
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition",
"attachment; filename=\"" + filename +
"\"");

Use the Content-Disposition HTTP header and set it to something like:
attachment; filename=myworkbook.xls
The is a Microsoft Knowledge Base Article all about this problem. And here is an example of setting Content-Disposition in Java code.

In addition to setting the headers for the content type, you'll also want to ensure that the server DOES NOT tell the browser to NOT CACHE the file.
In IE land, if you tell IE not to cache the file, it happily downloads the file... then tries to open the file from the directory it saved the file to... However since the headers said "don't cache" it takes this literally, and doesn't save the file, thus Excel throws an error saying, "There is no file!".
Long story short, tell IE to CACHE the file.

Related

Save as of pdf in IE doesn't save in the same name as filename [duplicate]

I am outputting a PDF file in a Web browser (IE8) HttpContext.Response.writefile(fileName) and it works great. When I try to save the file, it will give me the name of the ashx handler as a default. I would like to actually pass the real name.
I tried to add header information as follow:
context.Response.AddHeader("content-disposition", "attachment; filename=" + fileInfo.Name);
And it works but I do not want the user to have to choose between open and save, i want the file to open normally and if the user chooses to save it then the dialog would give him/her the default filename.
I tried also:
context.Response.AddHeader("content-disposition", "inline; filename=" + fileInfo.Name);
Or just, like Scott Hanselman suggested in his blog.
context.Response.AddHeader("content-disposition", "filename=" + fileInfo.Name);
None of those work for me. Does anybody have any ideas?
See test cases at http://greenbytes.de/tech/tc2231/#inlwithasciifilenamepdf - it seems that this is simply a missing feature in IE.
I also came across this problem.
What helped me was to also set the contenttype to application/pdf (instead of application/x-pdf, which is outdated)
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "inline; filename=\"Report.pdf\"");
In case of INLINE, it seems that Internet explorer is using the last parameter in the URL to build the filename.
For example if your url is http://doc.com/131231231
IE will prompt you to save the file as 131231231.pdf
If you need a filename for example foo_131231231.pdf
you can hack the IE by using this url: http://doc.com/foo_131231231
You may suffer to change your app a bit to expect such ugly parameter, but at the end your app
will work as you expect.

Why does Apache POI XSSF fail to write to servlet response outputStream?

I've created a servlet which creates an XSSFWorkbook and writes it to the response's outputStream. Strangely enough, when I try to test the functionality in the browser (Chrome v54.0.2840.98) I'm only able to get the xlsx file once (the file opens up without any formatting issues and has the expected content as well) but if I navigate away from the page where this feature is available with the 'back' button in the browser and go immediately back to same page and try to get the same file again I'm not getting anything in the response. Additionally, my other servlets stop working too until I open a new tab. I've given it a shot in a different browser (Safari v9.1.2 (11601.7.7)) and everything is working as expected, no issues whatsoever.
Here's the code that I use:
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
DateTime now = new DateTime();
Workbook workbook = createWorkbook(); //creates an XSSFWorkbook
response.setContentType("application/vnd.ms-excel");
response.setHeader(
"Content-Disposition",
"attachment; filename=\"excel-export-" + now.toString("yyyy-MMM-dd") + ".xlsx\""
);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(response.getOutputStream());
workbook.write(bufferedOutputStream);
}
When I'm running the code in the development env I don't get any exception, the status is 200 but still nothing gets downloaded. Ocassionally I get a
org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException:Fail to save: an error occurs while saving the package : The part /docProps/core.xml fail to be saved in the stream with marshaller org.apache.poi.openxml4j.opc.internal.marshallers.ZipPackagePropertiesMarshaller
Which, after extensive debugging, I can reproduce by passing a null to the workbook.write() function:
workbook.write(null);
Any help is appreciated, thank you for reading!
Javax Servlet API v2.5
Apache-POI v3.15
Java 8 JDK(1.8.0_111)
UPDATE
If I get an exception it looks like this(stacktrace):
https://gist.githubusercontent.com/darkstar85/b151e53b64498e1fb476d0f6f8ea4eaf/raw/ffb078c54b850922fcd4e467a6ebf9695aeb7354/gistfile1.txt
When looking at the code of Apache POI, this can only happen if StreamHelper.saveXmlInStream(xmlDoc, out) returns false. Additionally this only returns false if XML-Transformation fails at the line trans.transform(xmlSource, outputTarget);.
However it just does a identity-transformation (i.e. a simple copy) here, so this can only fail, if the XML Parser that is available in your application somehow does not work correctly.
Therefore I would check which JDK you are using and if there are any additional XML Parsers added in your application, e.g. Xerces or any other and see if you can remove them.

Content-Disposition file extension not properly working on Firefox

I have the following code on Spring Controller
#RequestMapping(value = "/download", method = RequestMethod.POST)
public void downloadActive(#RequestParam(value = "type") String offerType, HttpServletResponse response,
HttpSession session) throws Exception {
StringBuilder b = new StringBuilder();.
.
.
response.addHeader("Content-Disposition: ", "attachment; filename=my" + offerType + "Offers.csv");
response.getWriter().write(b.toString());
..
}
This code get executed when a download button from EXt Js is clicked. On chrome, it directly downloads the file as a *.csv format and when the user opens it, it will use Excel automatically to open the file, if they already have installed and this is the right behavior I wanted to have.
However, on firefox, it prompts a save as window with open with and save options. If I use open with option, it tells me the filename is filename.csv but the type is chrome htm file. I haven't mentioned htm anywhere in my code and I dont know why its trying to open it as htm instead of csv file. Once it tries to open it, it brings excel application and the contents are in a bad format.
Is there a way to avoid this problem on firefox ?
Thanks
Adding double quotes (") for the file name fixes the problem.
response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + "");
Even if I am not sure why it worked, changing the addHeader Method to setHeader fixed the issue.
response.setHeader("Content-Disposition: ", "attachment; filename=my" + offerType + "Offers.csv");
PrintWriter printWriter = resourceResponse.getWriter();
java.util.Date date = new java.util.Date();
resourceResponse.setContentType("text/csv");
resourceResponse.addProperty(HttpHeaders.CACHE_CONTROL,
"max-age=0, must-revalidate");
resourceResponse.setProperty(
HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + "export_build" + "_"
+ date.getTime() + ".csv");
printWriter.write(stringBuilder.toString());
Make sure to write the content after printing the header to ensure content is packaged in a file properly.

Java file download code design problem

I have a Java project which is used as a component in a webapp. This java code writes an xls file in a specific folder. I want to provide a download functionality for this file which should be triggered as soon as file writing is done.
The problem is - without a server environment, how can write a download functionality?
Don't write to file in a specific folder. Just write to the HTTP response body immediately. The downloading job should just be done in the webapp's code. I assume that you're using Servlets. If you set the HTTP response Content-Disposition header to attachment, then the browser will pop a Save as dialogue. If you also set the Content-Type header, then the browser will understand what to do with it (e.g. it will then be able to ask Do you want to open it in Excel or to save? and so on).
response.setHeader("Content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
// Now write xls to response.getOutputStream() instead of FileOutputStream.
If the API of that Java project is well designed, then you should have a method something like this:
public void writeXls(OutputStream output) throws IOException {
// Do your job to write xls to output. E.g. if you were using POI HSSF:
// WritableWorkbook workBook = Workbook.createWorkbook(output);
// ...
}
This way you can call it in the servlet as follows after setting the aforementioned headers:
yourClass.writeXls(response.getOutputStream());
Even more, it could easily be reused/tested in a plain vanilla Java application like follows:
yourClass.writeXls(new FileOutputStream("/path/to/foo.xls"));
This is how i do it. I show a download sql in my page.
response.setHeader("Content-Disposition", "attachment; " +
"filename=ContactPurge.sql");
response.setContentType("application/x-sql-data");
response.getWriter().write(procsql);
response.getWriter().write(sql);
response.flushBuffer();

open/save file in smartGWT

I have implemented RPCService, RPCServiceAsync & RPCServieImpl. On clicking a button a service in server side will be called and it will fetch data from DB and file is created. Once the file is created, then i need to open that file in client side and need to prompt a dialog box with open/save options.
how can i implement this opening a file part. pls suggest a way to implement t.. Reply pls.. thanks in advance....
#Hambend : I still have one more clarification !.. how to call this doGet method in another servlet i.e. in my onmodule load class i am having lot of widgets in seperate layout and one such a widget is BUTTON ? onclicking this button service RPCServiceImpl is called and all manipulations are done and file is created in a serperate function (public int GenerateFile(String name)() ) . how to make that function to call doGet method ? since doGet needs request,response parameters to be passed along with it?? pls suggest me a method to call that method. thanks in advance
GWT's RPC services are only able to send java objects back to the client. To send a file back to the user you'll need to use a non-GWT java servlet. Here's some code I've used before for serving up jpeg images from a repository.
public class ImageServlet extends HttpServlet {
private final String repository = "/var/images/";
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String filename = request.getParameter("file");
// Security: '..' in the filename will let sneaky users access files
// not in your repository.
filename = filename.replace("..", "");
File file = new File(repository + filename);
if (!file.exists())
throw new FileNotFoundException(file.getAbsolutePath());
response.setHeader("Content-Type", "image/jpeg");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-disposition", "attachment;filename=\"" + filename + "\"");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
byte[] buf = new byte[1024];
while (true) {
int length = bis.read(buf);
if (length == -1)
break;
bos.write(buf, 0, length);
}
bos.flush();
bos.close();
bis.close();
}
}
"Content-disposition: attachment" should cause most browsers to download the file instead of displaying it, with the filename defaulting to whatever you provide. The way you would use this servlet is to have the user call the RPCService that you already have, which saves the file to the repository folder. Then, you link or redirect them to this servlet with a url such as http://your.domain.com/fileServlet?file=myFile.jpg. Obviously with this setup you have a security risk where users can download other people's files if they can guess the filenames.
What you might like to do is merge the database code from your RPC service into this servlet. There's no need to save the file anywhere on the server, you can take your database results and write them into response.getOutputStream() or response.getWriter() in exactly the same way you would write them to file, except that the result goes straight to the user. As long as you set your content headers correctly the user won't notice the difference.
You can't call this method from another servlet, the only way to make a browser to download it as a file is to access it through a normal HTTP request. First you declare the servlet in your web.xml file like you would a GWT RPC service:
<servlet>
<servlet-name>ImageServlet</servlet-name>
<servlet-class>
com.package.ImageServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ImageServlet</servlet-name>
<url-pattern>/imageServlet</url-pattern>
</servlet-mapping>
Now any HTTP GET requests going to http://your.tomcat.server/webapp/imageServlet will get picked up by ImageServlet.doGet(). Then on the client side you can either make a normal html link to the file:
new HTML("<a href='" + GWT.getHostPageBaseURL() + "imageServlet?file=" + filename + "'>download</a>");
...or, you should be able to put this in a ClickHandler (I haven't tested it):
Window.Location.assign(GWT.getHostPageBaseURL() + "imageServlet?file=" + filename);
If the file is text, then you always back back an Object with an array of Strings.
If binary then simply a byte[] in the class would do.

Categories

Resources