-1

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

avalon
  • 2,231
  • 3
  • 24
  • 49

3 Answers3

3

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.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks, but response.getOutputStream() was the first option I tried, but got 'getWriter() has already been called for this response'. Then I found that I should call getWriter() method, but writer does not support write an array of bytes, etc. – avalon May 12 '16 at 14:04
  • Just fix that exception so you can keep using `getOutputStream()`. http://xyproblem.info – BalusC May 12 '16 at 14:08
  • Just fix? How? Stackoverflow keep telling me that I should use getWriter in all cases. – avalon May 12 '16 at 14:11
  • Naildown the one responsible for calling `getWriter()` and make it stop. – BalusC May 12 '16 at 14:12
  • This is JSF 2 part, I think I can't make it stop, as this is internals. I never call any of those methods implicitly before this piece of code – avalon May 12 '16 at 14:16
  • I can't help you based on the information provided so far (just ask a normal question about X instead of the current question about Y), but I can at least tell you that this is not the default behavior. – BalusC May 12 '16 at 14:22
0

The solution is trivial:

 FacesContext.getCurrentInstance().getExternalContext().responseReset();

And that's it!!

Thanks for your help.

avalon
  • 2,231
  • 3
  • 24
  • 49
0

I solved this by adding the next line:

JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, new JREmptyDataSource());
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109