We have the below requirement.
We will have to create an excel/pdf report and then download it on click of a button in a java web application. The pdf/excel file is dynamically created using application data.
We should not create any physical file on the server.
How do we go about this? Are there any streams through which I can read and write in the same go without having to close in between.
You could use memory-based streams (such as ByteArrayInputStream and ByteArrayOutputStream) and use the same underlying byte buffer to address the read/write in the same go part of the question.
As others have pointed out, you can just write directly to the output stream of the response.
Look at ServletResponse.getOutputStream().
You need to write to this stream from the one created by your report API. Don't forget to set the proper content-type using setContentType() method of the same class.
Here you can find how you can do it with jxl API and it may help you also.
How do I output an Excel file from a Servlet?
Whatever PDF or Excel API you are using to generate the files, you should lookup the constructor or method which takes an OutputStream to write the generated PDF/Excel content to. You should just feed it with response.getOutputStream() instead of FileOutputStream.
For example, iText for PDFs:
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
PdfWriter pdfWriter = PdfWriter.getInstance(document, response.getOutputStream());
// ...
And Apache POI for Excel:
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
WritableWorkbook workBook = Workbook.createWorkbook(response.getOutputStream());
// ...
Have a Servlet serve the pdf/excel file as a byte array.
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
byte[] bytes = null; // get this from somewhere in your app
String fileName = "filename.pdf"; // whatever you wish to name the file
ServletOutputStream out = response.getOutputStream();
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
response.setContentType("application/pdf");
response.setContentLength(bytes.length);
out.write(bytes);
out.flush();
}
MIME type for MS Excel files would be application/vnd.ms-excel.
Related
Following is Java code used to download file in Spring MVC Ajax call.
I need to set Content Length which I am unable to find using URL.openStream().
URL fileToDownload = new URL(form.getDownloadLink());
InputStream fileContents = fileToDownload.openStream();
response.setContentType("application/docx");
response.setHeader("Content-Disposition", "attachment; filename="+fileName+"");
response.setContentLength(<Length>);
ServletOutputStream outputFile = response.getOutputStream();
IOUtils.copy(fileContents, outputFile);
response.flushBuffer();
fileContents.close();
outputFile.close();
Could anyone guide how to get length of Stream?
We download PDF and DOCX files of different sizes using above
This question already has answers here:
Easy way to write contents of a Java InputStream to an OutputStream
(24 answers)
Closed 6 years ago.
So this is the code I have, which already works:
public class MyServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws Exception {
String pathToFile = "myimage.jpg";
File file = new File(pathToFile);
response.setHeader("Content-Type", "image/jpeg");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
Files.copy(file.toPath(), response.getOutputStream());
response.flushBuffer();
}
}
However, I must make this work with JDK 1.6.
Files.copy is only available with Java 1.7.
Any suggestions?
You can use Apache commons IOutils.
IOUtils.copy(InputStream input, OutputStream output)
Java 6 didn’t comes with any ready make file copy function, you have to manual create the file copy process. To copy file, just convert the file into a bytes stream with FileInputStream and write the bytes into another file with FileOutputStream.
As there's no way to do this a lot easier with JDK methods.You could use IOUtils from Apache Commons IO, it also has a lot of other useful things.
IOUtils.copy(inputStream, outputStream);
Or else using Guava's ByteStreams.copy() you can achieve the same functionality.
ByteStreams.copy(inputStream, outputStream);
There is an interesting error on a page. I wonder if you have any idea about it.
In order to download a file, we write the file to responseStream but if file is less than 8,3KB, we get file not found error although file is there.
If i increase the file size (using some dummy values), it works
I suspect it has something to do with the contentLength of response but it seems fine to me
file = new File(ef.getPath());
response.setContentLength((int) file.length());
fileIs = new FileInputStream(file);
FileCopyUtils.copy(fileIs, response.getOutputStream());
Please help me if you have any idea?
How try with adding Content-Disposition header and setContentType()
response.setHeader("Content-Disposition", "attachment; filename=\""+ fileName + "\"");
String mimeType = new MimetypesFileTypeMap().getContentType(fileName);
response.setContentType(mimetype);
When I want to write the full contents of a file into an OutputStream, I usually allocate a buffer as a byte[], then make a for loop to read data from the file's InputStream into the buffer and write the buffer contents into the OutputStream, until the InputStream has no more bytes available.
This seems rather clumsy to me. Is there a better way to do this?
Also, I am always unsure about the buffer size. Usually, I am allocating 1024 bytes, because it just feels good. Is there a better way to determine a reasonable buffer size?
In my current case, I want to copy the full contents of a file into the output stream that writes the contents of an HTTP response. So, this is not a question about how to copy files on the file system.
For Java 1.7+ you can use the Files.copy(Path, OutputStream), e.g.
HttpServletResponse response = // ...
File toBeCopied = // ...
try (OutputStream out = response.getOutputStream()) {
Path path = toBeCopied.toPath();
Files.copy(path, out);
out.flush();
} catch (IOException e) {
// handle exception
}
Note, since you are dealing with HttpServletResponse is is also a good idea to set correct response headers. Add the following lines before you copy the actual file data to the response:
String mimeType = URLConnection.guessContentTypeFromName(toBeCopied.getName());
String contentDisposition = String.format("attachment; filename=%s", toBeCopied.getName());
int fileSize = Long.valueOf(toBeCopied.length()).intValue();
response.setContentType(mimeType);
response.setHeader("Content-Disposition", contentDisposition);
response.setContentLength(fileSize);
Note, the encoding of the file name passed to the content disposition is important, see this question.
Apache Commons-IO:
IOUtils.copy(fileInputStream,outputStream);
JDK NIO
new FileInputStream(file).getChannel().transferTo(otherChannel);
With commons-io you have a one-line solution:
IOUtils.copy(yourFileInputStream, outputStream);
Note that you'd have to close your streams manually (or by IOUtils.closeQuitely(..))
I know this is a little broad, but here's the situation:
I am using JSP and Java. I have a file located on my server. I would like to add a link to the screen that, when clicked, would open the file for the user to view. The file can either appear in a window in the web browser, or pop up the program needed to open the file (similar to when you are outputting with iText to the screen, where Adobe opens to display the file). I know my output stream already, but how can I write the file to the output stream? Most of what I have read has only dealt with text files, but I might be dealing with image files, etc., as well.
Any help is appreciated!
Thanks!
You need to add certain fields to the response. For a text/csv, you'd do:
response.setContentType("text/csv"); // set MIME type
response.setHeader("Content-Disposition", "attachment; filename=\"" strExportFileName "\"");
Here's a forum on sun about it.
Here's a simple implementation on how to achieve it:
protected void doPost(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException,
IOException {
// extract filename from request
// TODO use a whitelist to avoid [path-traversing][1]
File file = new File(getFileName(request));
InputStream input = new FileInputStream(file);
response.setContentLength((int) file.length());
// TODO map your file to the appropriate MIME
response.setContentType(getMimeType(file));
OutputStream output = response.getOutputStream();
byte[] bytes = new byte[BUFFER_LENGTH];
int read = 0;
while (read != -1) {
read = input.read(bytes, 0, BUFFER_LENGTH);
if (read != -1) {
output.write(bytes, 0, read);
output.flush();
}
}
input.close();
output.close();
}
You need to create a 'download' servlet which writes the file to the response output stream with correct mime types. You can not reliably do this from within a .jsp file.
We usually do it with a 'download servlet' which we set the servletmapping to /downloads, then append path info to identify the asset to serve. The servlet verifies the request is valid, sets the mime header then delivers the file to the output stream. It's straightforward, but keep the J2EE javadocs handy while doing it.