无法显示从Primefaces中的流式内容生成的p:media中的PDF [英] Unable to show PDF in p:media generated from streamed content in Primefaces

查看:121
本文介绍了无法显示从Primefaces中的流式内容生成的p:media中的PDF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试显示在新的浏览器窗口中打开的嵌入式PDF.我有以下情况:

I'm trying to show inline PDF which is opened in new browser window. I have following scenario:

  1. 在一些由ajax调用的ActionListen中,我生成PDF内容,将数据放入会话中,然后发送要执行的Javascript(window.open打开新页面以显示PDF)
  2. 在打开的页面上,我仅在h:body中包含p:media标记,其值指向StreamedContent:

  1. In some ActionListen which is called by ajax I generate PDF content, put data in session, and send Javascript to be executed (window.open to open new page to show PDF)
  2. On opened page I just have p:media tag inside h:body with value pointing to StreamedContent:

现在,在该页面上未生成我的PDF.在日志中,我可以看到这两行:

Now, on that page my PDF is not generated. In log I can see these two lines:

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

我开始调试并发现一些问题.

I started to debug and find out a few things.

首先,我在RequestScoped bean的@PostConstruct方法中添加了断点.有趣的是,断点达到了两次,而PDF完美显示后,令我感到惊讶的是!

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

通过PrimeResourceHandler进行一些调试后,我发现在某些情况下ValueExpression未被计算,实际上它抛出了NullPointerException,并且在调试时,我再次看到发送了两个请求,第二个请求失败,因为<在第一个请求中删除了c9>,并且第二次调用handleResourceRequest没有意义.

After some debugging through PrimeResourceHandler I figure out that in some cases ValueExpression is not calculated, in fact it throws NullPointerException, and again while debugging I saw that two requests are sent, and second request fails because dynamicContentId is removed in first request, and second call to handleResourceRequest doesn't have sense.

通过Firebug,我可以看到两个请求,第一个请求适用于PDF数据,第二个请求也适用于内容类型application/pdf,但为空,大小为0.

Through Firebug I can see two requests, first which is good with PDF data, and second which is also with content-type application/pdf but empty, with size 0.

xhtml页面:

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

支持bean:

@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;
    }
}

我需要了解为什么在页面上使用p:media标签发送了两个请求,并弄清楚了如何进行这项工作.支持bean受请求限制,它在@PostConstruct方法中创建StreamedContent,并且具有该字段的getter和setter. Primefaces版本是3.4.2,带有Mojarra 2.1.14.

I need to understand why two requests are sent on page with p:media tag, and to figure out how to make this work. Backing bean is request scoped, it creates StreamedContent in @PostConstruct method, and has getter and setter for that field. Primefaces version is 3.4.2, with Mojarra 2.1.14.

添加:

很容易重现我的问题.如果init方法中的代码被替换为以下内容:

It is easy to reproduce my problem. If code in init method is replaced with following:

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

问题可以重现.

推荐答案

我可以重现您的问题.实际上,它在Firefox中也不起作用(在IE9中也不起作用,但在Chrome中有效). PrimeFaces领导Cagatay还提到几次.

I can reproduce your problem. It indeed doesn't work in Firefox (nor in IE9, but it works in Chrome). PrimeFaces lead Cagatay has also mentioned that several times.

我不确定这是否是PrimeFaces资源处理程序或浏览器中的错误.我将其留在中间.

I'm not sure if this is a bug in the PrimeFaces resource handler or in the browser. I'll leave it in the middle.

与此同时,最好的选择是简单的网络servlet .只需创建此类:

In the meanwhile, your best bet is a simple web servlet for the job. 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);
    }

}

并按如下所示调用它:

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

就是这样.无需XML配置.它适用于所有浏览器.根据功能要求,您可能需要进一步微调与浏览器缓存相关的响应标头.

That's it. No XML config necessary. It works for me in all browsers. Depending on the functional requirements, you may want to further finetune response headers related to browser caching.

这篇关于无法显示从Primefaces中的流式内容生成的p:media中的PDF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆