I use jasper reports version 6.2.1 with the following configuration:
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
JREmptyDataSource jasper = new JREmptyDataSource();
JasperPrint jasperPrint = jasperFillManager.fillReport(this.getClass().getClassLoader().getResource("/reports/tn2.jasper").getPath(), null, jasper);
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment" + "; filename=hehe.pdf");
ByteArrayOutputStream finalReport = new ByteArrayOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint,finalReport);
PrintWriter ouputStream = response.getWriter();
ouputStream.write(new String(finalReport.toByteArray()));
ouputStream.flush();
FacesContext.getCurrentInstance().responseComplete();
I do it from my JSF 2.x backing bean.
But I always get a blank page when try to export to stream. But if I do:
JasperExportManager.exportReportToPdfFile(jasperPrint,
"d://hehe.pdf");
it works ok, I see the content in the generated file. How to force it work with streams? I tried to close/flush streams in different configurations, use ARM, etc. No luck so far
This part is wrong.
ByteArrayOutputStream finalReport = new ByteArrayOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint,finalReport);
PrintWriter ouputStream = response.getWriter();
ouputStream.write(new String(finalReport.toByteArray()));
You're allocating a byte array in memory. Then you're exporting the report to it. Then you're converting the byte array to string (which is basically a character array). Then you're writing it to a character based writer. Basically, you've corrupted the binary content of the PDF file by converting all bytes to characters in a fairly inefficient and platform-dependent way. It's as if you're opening the PDF file in a text editor like Notepad and then saving it as a TXT file. Such a file is not anymore readable by a PDF reader.
You should just stream the bytes unmodified to the byte based output stream. Replace all of above by the below oneliner.
JasperExportManager.exportReportToPdfStream(jasperPrint, response.getOutputStream());
Unrelated to the concrete problem, since JSF 2.x, ExternalContext offers several delegate methods without the need to cast down to HttpServletResponse. See also How to provide a file download from a JSF backing bean? for a concrete example.
The solution is trivial:
FacesContext.getCurrentInstance().getExternalContext().responseReset();
And that's it!!
Thanks for your help.
I solved this by adding the next line:
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, new JREmptyDataSource());
Related
I'm studying Mp4Parser API (Mp4Parser GitHub) and try to learn how it's working. I first tried to create an MP4 by "copying" the highest level tags into a new file.
If I get a similar file, it's unfortunately not "the same file" and result can't be played.
My dirty (it's just a quick try) code is:
public void copy(String videoFilePath) throws IOException {
File videoFile = new File(videoFilePath);
File videoPro2 = new File("/tmp/output.mp4");
if (videoPro2.exists())
videoPro2.delete();
videoPro2.createNewFile();
FileOutputStream fos = new FileOutputStream(videoPro2);
IsoFile isoFile = new IsoFile(new FileInputStream(videoFilePath).getChannel());
IsoFile pro2 = new IsoFile(new FileInputStream(videoPro2).getChannel());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pro2.addBox(Path.getPath(isoFile, "ftyp[0]"));
pro2.addBox(Path.getPath(isoFile, "free[0]"));
pro2.addBox(Path.getPath(isoFile, "moov[0]"));
pro2.addBox(Path.getPath(isoFile, "mdat[0]"));
pro2.getBox(Channels.newChannel(baos));
baos.writeTo(fos);
isoFile.close();
pro2.close();
baos.close();
return;
}
I tested my original MP4 with AtomicParsley, saw there were in that order, a ftyp, a free, a moov and an mdat tags.
My method basically aims to get these four tags and puts them into the destination file to "make an exact copy". Or that's what I was expecting, but it's not the case.
Firstly, output.mp4 is not playable, but comparing the hex dumps of input and output... almost everything is different, except ftyp and free. Why?
I can see that tag size are not similar neither..
Obviously, my goal is not to "copy" files, but understand Mp4Parser API as I'd like to use it in a real project. But this copy method is a starter for me to understand how this works, as I'm not familiar with MP4 specification.
Thanks
Ok, my fault.
There was an UUID tag I missed in the original footage between moov and mdat tags. Copying the UUID tag using
pro2.addBox(Path.getPath(isoFile, "uuid[0]"));
just before adding the mdat atom does the trick.
Sorry for this :)
I created a pdf file based on the thymeleaf template i'm actually using the template resolver, flying saucer, to write the file on the output stream
but since i can't access the front in order to define the content of the recap which would be generated every now and then when the client needs to, i thought it would be better to generate the pdf file on the server side. So my question is:
Is there a way to get the output stream where my data is written and convert it in order to
write on the fly so it won't be created in the local storage
Here's a part of my business logic:
os = new FileOutputStream(pdf);
ITextRenderer renderer = new ITextRenderer();
renderer.layout();
renderer.createPDF(os);
i use this in my controller and i use attachement content attribut in the response entity
other then that i'm open to any suggestions
thanks in advance
I had a similar task some time ago for a simple Java EE + JSF project and here's how I did it:
byte[] asPdf = .... (your pdf data)
String filename = "demo.pdf";
HttpServletResponse response = Faces.getResponse(); // Using Omnifaces in this example, but that is irrelevant
// Details: https://stackoverflow.com/a/9394237/7598851
response.reset();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
response.setContentLength(asPdf.length);
response.setCharacterEncoding("UTF-8");
try (OutputStream output = response.getOutputStream()) {
output.write(asPdf);
} catch (IOException e) {
// ...
}
The complete project is here, the relevant code is in this file
protected static byte[] exportReportToPdf(JasperPrint jasperPrint)
throws JRException {
JRPdfExporter exporter = new JRPdfExporter();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
exporter.setParameter(JRPdfExporterParameter.PDF_JAVASCRIPT,
"this.print({bUI: true,bSilent: false,bShrinkToFit: true});");
exporter.exportReport();
return baos.toByteArray();
}
We are using code like this to export a PDF document from a Jasper application.
The line
exporter.setParameter(JRPdfExporterParameter.PDF_JAVASCRIPT,
"this.print({bUI: true,bSilent: false,bShrinkToFit: true});");
adds JavaScript to send the PDF document directly to the printer.
The expected behavior is that a print dialog will come up with a preview of the PDF document.
This works fine most of the time - except I am having problems about one out of every 5-6 times in Internet Explorer 8 and Firefox.
What happens is - the print preview dialog with the PDF document does not appear or it appears with a blank document in the preview window.
-I've tried a number of different JavaScripts (different params to this.print() via exporter.setParameter
-I've tried setting different response headers such as
response.setContentType("application/pdf");
response.setHeader("Content-disposition","inline; filename=\""
+ reportName
+ "\"");
response.setContentLength(baos.size());
these did not seem to help
This seems to be an IE and FF issue. Has anyone ever dealt with this problem? I need to get it to work across all browsers 100% of the time. Perhaps a different approach to accomplish the goal of sending the PDF document export directly to the printer? or a third party library that will work across browsers?
Maybe it isn't getting a chance to update the UI. The following code delays the print perhaps giving it the chance it needs. I didn't test as I don't have your environment.
exporter.setParameter(JRPdfExporterParameter.PDF_JAVASCRIPT,
"app.setTimeOut('this.print({bUI: true,bSilent: false,bShrinkToFit: true});',200);")
I have an xml file already being created and rendered as a PDF sent over a servlet:
TraxInputHandler input = new TraxInputHandler(
new File(XML_LOCATION+xmlFile+".xml"),
new File(XSLT_LOCATION)
);
ByteArrayOutputStream out = new ByteArrayOutputStream();
//driver is just `new Driver()`
synchronized (driver) {
driver.reset();
driver.setRenderer(Driver.RENDER_PDF);
driver.setOutputStream(out);
input.run(driver);
}
//response is HttpServletResponse
byte[] content = out.toByteArray();
response.setContentType("application/pdf");
response.setContentLength(content.length);
response.getOutputStream().write(content);
response.getOutputStream().flush();
This is all working perfectly fine.
However, I now have another PDF file that I need to include in the output. This is just a totally separate .pdf file that I was given. Is there any way that I can append this file either to the response, the driver, out, or anything else to include it in the response to the client? Will that even work? Or is there something else I need to do?
We also use FOP to generate some documents, and we accept uploaded documents, all of which we eventually combine into a single PDF.
You can't just send them sequentially out the stream, because the combined result needs a proper PDF file header, metadata, etc.
We use the iText library to combine the files, starting off with
PdfReader reader = new PdfReader(/*String*/fileName);
reader.consolidateNamedDestinations();
We later loop through adding pages from each pdf to the new combined destination pdf, adjusting the bookmark / page numbers as we go.
AFAIK, FOP doesn't provide this sort of functionality.
<%
response.reset();
response.setHeader("Content-Disposition", "attachment;filename=\"" + "test.xls\"");
response.setHeader("Content-Transfer-Encoding", "binary");
response.setContentType("application/vnd.ms-excel");
InputStream is = new FileInputStream(realPath);
//OutputStream outStream = response.getOutputStream();
JasperPrint jasperPrint = JasperFillManager.fillReport(is,
parameters, new JRBeanCollectionDataSource(pdfList));
JRAbstractExporter exporter = new JExcelApiExporter();
exporter.setParameter(JExcelApiExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JExcelApiExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
exporter.setParameter(JExcelApiExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
exporter.setParameter(JExcelApiExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
exporter.setParameter(JExcelApiExporterParameter.OUTPUT_STREAM, out);
exporter.exportReport();
outStream.flush();
outStream.close();
out.clear();
out =pageContext.pushBody();
%>
we use the code above to generate an excel, and it works well in tomcat + windows, but after we upload to linux + weblogic server, the excel is corrupted. I use text editor to open the excel, I found it add several empty line in the excel, which caused the excel can not be open successfully, anyone can point me the right direction ? Why there are space ? How it comes ?
Thanks in advance !
I suspect that your use of pageContext.pushBody() may be the culprit.
pushBody is, as far as I know, meant for updating the output in the scope of a JSP tag.
When you are generating binary content such as an excel file, where you need to be absolutely sure that the intended bytes, and only the intended bytes reach the browser, you need to write those bytes, flush the output, and then make sure that nothing else gets written. By invoking pushBody(), you are making it so that more content can be written to the output, and any blank lines (and the carriage returns / line feeds between them) in the JSP page could be output.
All in all, I suggest that you just not do this in a JSP - do it in a Servlet instead.