Downloading Excel file from server using servlets - servlets

I have an Excel file on the server side. How I can display it on client side browser using servlets?
Thanks in advance.

To the point: just get an InputStream of it somehow (FileInputStream is suitable) and write it to the OutputStream of the response the usual Java IO way. That's basically all. You'll only need to take care that you set the right response headers, so that the browser understands what to do with it. The Content-Type header will instruct the webbrowser what kind of file it is so that the browser knows which application to use to open it.
Here's a kickoff example:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String filename = URLDecoder.decode(request.getPathInfo(), "UTF-8");
File file = new File("/path/to/files", filename);
response.setHeader("Content-Type", getServletContext().getMimeType(file.getName()));
response.setHeader("Content-Length", file.length());
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file));
output = new BufferedOutputStream(response.getOutputStream());
byte[] buffer = new byte[8192];
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
} finally {
if (output != null) try { output.close(); } catch (IOException ignore) {}
if (input != null) try { input.close(); } catch (IOException ignore) {}
}
}
Map this servlet in web.xml on an url-pattern of /files/* so that you can get the excel file by http://example.com/contextname/files/filename.xls.
If it's actually an xlsx file, which isn't by default recognized by the average servletcontainer yet (the ServletContext#getMimeType() would then return application/octet-stream instead of the desired xlsx content type), then you need to add the following entry to the web.xml as well:
<mime-mapping>
<extension>xlsx</extension>
<mime-type>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</mime-type>
</mime-mapping>
For a more advanced example of a file servlet you may find this article useful as well, it supports under each download resumes as well.

Related

How to do GZIP compression while writing directly to response

I am trying to compress my response when the request header contains gzip in Accept-Encoding. However, adding following to app.properties only works when controller method is returning an object.
server.compression.enabled=true
server.compression.min-response-size=1
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
I am writing directly to response stream. So, above compression properties don't work.
My method looks like this:
#GetMapping(path = "/something", produces = MediaType.TEXT_PLAIN_VALUE)
public void getSomething(#RequestParam(name = "paramA") String paramA,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
PrintWriter writer = null;
if (request.getHeader("Accept-Encoding").contains("gzip")) {
writer = new PrintWriter(new OutputStreamWriter(new GZIPOutputStream(response.getOutputStream())));
response.addHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
} else {
writer = response.getWriter();
}
final PrintWriter fwriter = writer;
someObjectInstance.getSomething(paramA).forEach(x -> {
fwriter.write(x.toString());
});
fwriter.flush();
}
When I curl the above method, I get an empty file.
I did try to use the GzipFilter by referring to the following link.
http://www.javablog.fr/javaweb-gzip-compression-protocol-http-filter-gzipresponsewrapper-gzipresponsewrapper.html, which works by the way.
However, the filter requires alot of boilerplate code. Is there a way I can make changes in controller method and solve the problem as in the link mentioned above.
Just realised I was not closing the writer.
After adding fwriter.close(); in the end, the problem was solved.

Download file with redirection

I am trying to make the user able to download a file
<h:commandLink value="yes" actionListener="#{Bean.readFileFromServer}"/>
the method redFileFromServer is a method that returns void, it does some logic then it calls anthoer method to return the file to the response
public void exportList() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset();
try {
userLogger.info("Exposting report ");
ec.setResponseContentType("application/octet-stream"); // Check
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + result.getFileName() + "\"");
OutputStream output = ec.getResponseOutputStream();
int octet;
while ((octet = input.read()) != -1) {
output.write(octet);
}
input.close();
output.close();
fc.responseComplete();
} catch (Exception e) {
e.printStackTrace();
}
}
the file downloaded is compressed zip file, I have 2 problems, first sometimes this works and sometimes not, and I don't know why the behavior is not consistence.Second problem if there is any exception the page is redirected, which is unacceptable duo to my structure design, I need this to work every time and in case of any problem the page won't redirect.

Using Open CSV to Send files from ServletOutputStream

I have parsed a JSON Object that was sent to my TOMCAT server using POST and turned it into a CSV file. I would like to send the CSV file back to the user. I am confused about how to send the file back because all the examples I have seen reference an actual file that is stored on the server - my file is built in memory and doesn't actually reference a file/file descriptor as far as I can tell.
//The doPost method has already generated the String[] - I then call generateCSV
protected void generateCSV(ArrayList<String[]> data, ServletOutputStream out,
HttpServletResponse response)
{
try{
BufferedWriter buff = new BufferedWriter(new OutputStreamWriter(out));
CSVWriter writer = new CSVWriter(buff);
writer.writeAll(data);
writer.close();
sendFile(response, out);
}catch(IOException | ServletException e){
e.printStackTrace();
}
}
protected void sendFile(HttpServletResponse response, ServletOutputStream outstream)throws ServletException, IOException
{
response.setContentType("application/octet-stream");
outstream.flush();
outstream.close();
}
What do you have to do to send a file to the user from a servlet?
Set the content-type.
Write out the bytes.
Seems to me you are doing this, but in the wrong order. Also, rather than using application/octet-stream you might want to actually tell the browser this is CSV. You might also want to give it a filename.
response.setContentType("text/csv");
response.setHeader("Content-Disposition","filename=whatever.csv");
BufferedWriter buff = new BufferedWriter(new OutputStreamWriter(out));
CSVWriter writer = new CSVWriter(buff);
writer.writeAll(data);
writer.close();

How to handle errors when using ASP.NET to create a zipfile for download?

I'm working on a functionality in my asp.net web site that enables the user to download some files as a zip file. I'm using the DotNetZip library to generate the zip file.
My code looks like this:
protected void OkbtnZipExport_OnClickEvent(object sender, EventArgs e)
{
var selectedDocumentIds = GetSelectedDocIds();
string archiveName = String.Format("archive-{0}.zip", DateTime.Now.ToString("yyyy-MMM-dd-HHmmss"));
AddResponseDataForZipFile(Response, archiveName);
try
{
string errorMessage = Utils.ExportToZip(selectedDocumentIds, arkivdelSearchControl.GetbraArkivConnection(), Response.OutputStream);
if (!string.IsNullOrEmpty(errorMessage))
{
LiteralExportStatus.Text = errorMessage;
}
else
LiteralExportStatus.Text = "Success";
}
catch (Exception ex)
{
LiteralExportStatus.Text = "Failure " + ex.Message;
}
Response.Flush();
Response.Close();
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
private void AddResponseDataForZipFile(HttpResponse response, string zipName)
{
Response.Clear();
Response.BufferOutput = false;
Response.ContentType = "application/x-zip-compressed";
Response.AddHeader("content-disposition", "attachment; filename=" + zipName);
Response.AddHeader("Expires", "0");
Response.AddHeader("Content-Description", "Zip Arcive");
}
Now, if anything goes wrong, say the Utils.ExportToZip method fails, I want to present an error message to the user and not the download dialog. Do I have to remove some data from the Response object in order to cancel the download operation?
Best regards
OKB
first, Don't call HttpContext.Current.ApplicationInstance.CompleteRequest();
Reference.
At one point, there was some example code that showed CompleteRequest(), but it's wrong.
Second - to do what you describe,
you'll need to insure that the zip file can be created correctly and in its entirety, before sending anything. That means you should do the AddResponseDataForZipFile() only after the zipfile is completely created. That means you need to create an actual zip file on the server, and not simply save out to Response.OutputStream. Once the file is successfully created, then call AddResponseDataForZipFile(), stream the bytes for the temp zip file, call Response.Close(), then delete the temporary zip file.
I can't comment at the moment, so take this answer as one.
How does Utils.ExportToZip work?
If the reason it takes the Response.OutputStream for the constructor is to write the zip-file directly into it, then you need to set Buffering in order to "undo" that in your AddResponseDataForZipFile Method:
Response.BufferOutput = true;

Get XML by Post method from Webservice in Flex

I created a servlet in java that will give me a xml response when called
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/xml; charset=utf-8"); // Set the servlet's response type to XML.
PrintWriter out = null;
try {
out = response.getWriter();
XMLOutputFactory of = XMLOutputFactory.newInstance();
XMLStreamWriter writer = of.createXMLStreamWriter(out);
writer.writeStartDocument();
writer.writeStartElement("Test");
for(int i = 1; i <= 100; i++) {
writer.writeStartElement("TheNumber");
writer.writeAttribute("number", "" + i);
writer.writeAttribute("value", "" + Math.pow(2, i));
writer.writeEndElement();
}
writer.writeEndElement();
writer.close();
out.close();
} catch (Exception ex) {
}
}
Now I want to get this xml in flex, can someone give me a hint? I tried mx:WebService and mx:HttpService but both of them did not work.
Thanks in advance
Sebastian
Since you've already solved your issue with HttpService, now it's time to graduate to using Flex remoting with their Granite Data Services or BlazeDS, unless you have some major reason you can't. Parsing XML and using XML for data transmission is a no-no, terrible performance, and in general a bad idea if you can avoid it.
http://www.graniteds.org/
http://opensource.adobe.com/wiki/display/blazeds/BlazeDS/
Just a straight URLLoader will work for you as well.

Resources