Cannot show PDF in p: media created by streaming content in Primefaces

I am trying to show the embedded PDF that opens in a new browser window. I have the following script:

  • In some ActionListen that is called by ajax, I generate PDF content, put the data into the session and send Javascript to execute ( window.open to open a new page for showing the PDF)
  • On an open page, I have a p:media tag inside h:body with a value pointing to StreamedContent :

Now, on this page my PDF is not generated. In the log I see two lines:

 org.primefaces.application.PrimeResourceHandler handleResourceRequest SEVERE: Error in streaming dynamic resource. Expression cannot be null 

I began to debug and learn a few things.

First, I added a breakpoint to the @PostConstruct method of my RequestScoped bean. What is interesting is that the breakpoint is reached twice, and to my great surprise, after the PDF is displayed perfectly ?!

After some debugging through PrimeResourceHandler I find out that in some cases ValueExpression not calculated, it actually throws a NullPointerException , and again during debugging I saw that two requests are sent and the second request fails because dynamicContentId is deleted in the first request. and the second call to handleResourceRequest does not make sense.

Through Firebug, I see two requests, firstly, it is good with PDF data, and secondly, it is also with the content type / pdf, but empty, with a size of 0.

xhtml page:

 <html> <h:head></h:head> <h:body> <p:media value="#{reportBean.streamedContent}" player="pdf" width="500" height="500"/> </h:body> </html> 

bean support:

 @RequestScoped public class StampaListeBackingBean implements Serializable { private static final long serialVersionUID = 1L; private StreamedContent streamedContent; @PostConstruct public void init() { Map<String, Object> session = FacesContext.getCurrentInstance().getExternalContext().getSessionMap(); byte[] b = (byte[]) session.get("reportBytes"); if (b != null) { streamedContent = new DefaultStreamedContent(new ByteArrayInputStream(b), "application/pdf"); } } public StreamedContent getStreamedContent() { if (FacesContext.getCurrentInstance().getRenderResponse()) { return new DefaultStreamedContent(); } else { return streamedContent; } } public void setStreamedContent(StreamedContent streamedContent) { this.streamedContent = streamedContent; } } 

I need to understand why two requests are sent to a page with the p:media tag and figure out how to do this. The backup bean is the request area, it creates the StreamedContent method in @PostConstruct and has getter and setter fields for this. The private version is 3.4.2, with Mojarra 2.1.14.

ADDED:

Easy to reproduce my problem. If the code in the init method is replaced with the following:

 FileInputStream fis = new FileInputStream(new File("C:\\samplexxx.pdf")); streamedContent = new DefaultStreamedContent(fis, "application/pdf"); 

The problem may be reproduced.

+8
stream pdf jsf-2 primefaces media
source share
3 answers

I can reproduce your problem. It really does not work in Firefox (and in IE9, but it works in Chrome). Cagatay Premier League also mentioned that several times .

I am not sure if this is a bug in the PrimeFaces resource handler or in the browser. I will leave it in the middle.

In the meantime, your best bet is a simple web servlet to work with. Just create this class:

 @WebServlet("/report.pdf") public class PdfReportServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { byte[] content = (byte[]) request.getSession().getAttribute("reportBytes"); response.setContentType("application/pdf"); response.setContentLength(content.length); response.getOutputStream().write(content); } } 

And call it like this:

 <p:media value="/report.pdf" ... /> 

What is it. No XML configuration required. It works for me in all browsers. Depending on the functional requirements, you may want to clarify the response headers related to browser caching.

+9
source share

This is not a problem with the browser or the conference, but simply a problem with the loss.

A getter is called twice through p: media (or if you refresh the page more), but only the first call gets the correct data. StreamedContent encapsulates an InputStream, which has the property that it will not give bytes if the stream is at the end of the file. The first time it is read to the end (the data is in order), but each subsequent call will not receive any data. :)

javadoc of inputStream.read () : If the byte is unavailable because the stream is at the end of the file, -1 is returned; otherwise, at least one byte is read and stored in b.

Decision

  private StreamedContent streamedContent; private InputStream stream; public void somewhere(){ byte[] b = ... stream = new ByteArrayInputStream( b ); stream.mark(0); //remember to this position! streamedContent = new DefaultStreamedContent(stream, "application/pdf"); } public StreamedContent getStreamedContent() { if (streamedContent != null) streamedContent.getStream().reset(); //reset stream to the start position! return streamedContent; } 
+4
source share

I hope that my little contribution can help anyone who cannot display a PDF view in Firefox. I used Primefaces 6 + Spring and I had the same problem, but maybe not for the same reason. Indeed, I tried the proposed solution from Balus C. It helped me display the PDF in Chrome and IE11, but it still did not work in Firefox 52.

I noticed an error in the Firefox console: Load denied by X-Frame-Options: http: // localhost: 8080 / myapp / does not allow framing

In my case, this was because the spring-security configuration and solution was edited by spring -context.xml as follows:

 <sec:http ...> ... <sec:headers> <sec:frame-options policy="SAMEORIGIN" /> </sec:headers> ... </sec:http> 
+2
source share

All Articles