PrimeFaces p:media无法与@ViewScoped bean中的StreamedContent一起使用 [英] PrimeFaces p:media not working with StreamedContent in a @ViewScoped bean

查看:93
本文介绍了PrimeFaces p:media无法与@ViewScoped bean中的StreamedContent一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在浏览器中存在与Primefaces4 meida类型渲染pdf文件有关的问题.我已经在primefaces网站的展示柜中成功尝试了该示例.现在,我想获得一个新功能,该功能在左面板中提供一个带有文档节点的树形结构.用户可以选择一个文档以将其显示在中心面板中.这意味着,一旦用户在树上的一个文档中进行选择,它将在backbean中生成pdf媒体字段.

I have an issue related to Primefaces4 meida type rendering pdf file in browser. I have successfully tried the example in showcase from primefaces website. Now I want to get a new feature, which offers an tree structure with document nodes in the left panel. User could select one document to display it in the center panel. That means it generates pdf media field in backbean once user selects on one document on the tree.

相关代码如下所示:

backbean:

@ManagedBean
@ViewScoped
public class DocumentsBean implements Serializable {

private static final long serialVersionUID = 3560539268513760978L;
private TreeNode root;
private String url;
private TreeNode selectedNode; 
private StreamedContent media;

public DocumentsBean() {
    root = new DefaultTreeNode("Root");
}

public TreeNode getRoot() {
    return root;
}

public TreeNode getSelectedNode() {  
    return selectedNode;  
}  

public void setSelectedNode(TreeNode selectedNode) {  
    this.selectedNode = selectedNode;  
}  

public void onNodeSelect(NodeSelectEvent event) {  
    File file = (File) this.selectedNode.getData();
    generatePDF(file);
}

public String getUrl() {
    return url;
}

public void setUrl(String url) {
    this.url = url;
}

public void explore() {
    root = new DefaultTreeNode(new File(this.url), null);
    constructDir(root);
}

/**
 * construct directory and its sub files.
 * @param parent
 */
private void constructDir(TreeNode parent) {
    File file = (File) parent.getData();
    File[] files = file.listFiles();
    for (File f: files) {
        if (f.isFile()) {
            new DefaultTreeNode("document", f, parent);
        } else {
            TreeNode subParent = new DefaultTreeNode(f, parent);
            constructDir(subParent);
        }
    }

}

private void generatePDF(File file) {
    PDFGenerator generator = new PDFGenerator(file);
    File pdf = generator.transformToPDF();

    if (pdf != null) {
        InputStream stream = null;
        try {
            stream = new FileInputStream(pdf);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        media = new DefaultStreamedContent(stream, "application/pdf");
    }

}

public StreamedContent getMedia() {
    return media;
}

}

部分观点:

<p:layoutUnit position="west" size="300" header="Directory Content" resizable="false" collapsible="true">
            <h:form id="docTree_form">
                <p:growl id="messages" showDetail="true" /> 
                <p:tree id="docTree" value="#{documentsBean.root}" var="node" animate="true" selectionMode="single" selection="#{documentsBean.selectedNode}" dynamic="true" cache="true">

                    <p:ajax event="select" update=":pdf_form:media" listener="#{documentsBean.onNodeSelect}" />
                    <p:treeNode expandedIcon="ui-icon-folder-open" collapsedIcon="ui-icon-folder-collapsed">
                        <h:outputText value="#{node.name}" />
                    </p:treeNode>

                    <p:treeNode type="document" icon="ui-icon-document">
                        <h:outputText value="#{node.name}" />
                    </p:treeNode>
                </p:tree>
            </h:form>
        </p:layoutUnit>

        <p:layoutUnit position="center" header="Center" resizable="true">
            <h:form id="pdf_form">
                <p:media id="media" value="#{documentsBean.media}"     player="pdf" width="100%" height="700px">  
                    Your browser can't display pdf 
                </p:media>
            </h:form>
        </p:layoutUnit>

运行此代码时,没有错误或异常.但是,Firefox没有生成PDF查看器.真的很奇怪!

When I run this code, there is no error or exception. However, there is no PDF viewer generated in Firefox. Really strange !

基于BalusC评论的后续问题:

a follow up question based on BalusC comments:

我的应用程序运行时出现此异常:

I got this exception when my app is running up:

SEVERE: Servlet.service() for servlet [Faces Servlet] in context with path     [/DocumentViewer_JSF] threw exception
java.lang.NullPointerException
at     org.primefaces.application.PrimeResourceHandler.handleResourceRequest(PrimeResourceHandler.java:114)

我发现此行导致了此异常:

I found that this line causing this exception:

return new DefaultStreamedContent();

如果我创建一个真实的pdf文件,该异常消失了.但是,如果用户未选择pdf文件,我真的不希望显示该文件.

If I create a real pdf file, the exception is gone. But I really don't want a pdf file displayed if user has not chosen the file.

推荐答案

您的具体问题是由于Web浏览器实际上是在物理上完全独立的HTTP请求中下载PDF文件,而不是在生成和发送HTML输出的HTTP请求中下载PDF文件.基于JSF源代码.您可能已经知道,通过javax.faces.ViewState隐藏输入字段将视图范围的bean绑定到特定的JSF视图.如果此更改或不存在,则请求将获得一个新的且具有不同视图范围的bean实例.

Your concrete problem is caused because the webbrowser is actually downloading the PDF file in a physically completely separate HTTP request than the HTTP request which is generating and sending the HTML output based on JSF source code. You probably already know that view scoped beans are tied to a particular JSF view via javax.faces.ViewState hidden input field. If this get changed or is absent, then the request gets a new and different view scoped bean instance.

换句话说,当浏览器在单独的HTTP请求中从服务器下载PDF文件时,它没有使用相同的@ViewScoped bean实例,而是获得了一个全新且完全独立的实例,而该实例没有拥有与绑定到页面的属性相同的属性(状态),因此,整个StreamedContent在那个时候就是null.

In other words, while the browser is downloading the PDF file from the server in a separate HTTP request, it isn't using the same @ViewScoped bean instance, but instead getting a brand new and completely independent instance which does not hold the same properties (state) as the one tied to the page and thus the whole StreamedContent is simply null at that point.

<p:media>StreamedContent的问题与<p:graphicImage>StreamedContent的问题基本上具有相同的理由,而该问题在之前已被多次回答:

This problem with <p:media> and StreamedContent has essentially the same grounds as the problem with <p:graphicImage> and StreamedContent which is answered several times before:

  • Display dynamic image from database with p:graphicImage and StreamedContent
  • Display database blob images in <p:graphicImage> inside <ui:repeat>
  • How to use p:graphicImage with StreamedContent within p:dataTable?

在您的特殊情况下,您需要重新设计整个束,以使DocumentsBean支持bean通过唯一的标识符将PDF文件存储在某个位置(例如,临时磁盘,服务器内存,数据库等),然后将该唯一标识符作为请求参数准确地传递给<p:media>,如下所示:

In your particular case, you need to redesign the whole bunch in such way that the DocumentsBean backing bean stores the PDF file in some place (e.g. temp disk, server memory, database, etc) by an unique identifier and then pass exactly that unique identifier along as request parameter to <p:media> as follows:

<p:media value="#{mediaManager.stream}" width="100%" height="700px" player="pdf">
    <f:param name="id" value="#{documentsBean.mediaId}" />
</p:media>

因此,MediaManager支持bean看起来像这样:

Whereby the MediaManager backing bean look something like this:

@ManagedBean
@ApplicationScoped
public class MediaManager {

    @EJB
    private MediaService service;

    public StreamedContent getStream() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();

        if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
            // So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
            return new DefaultStreamedContent();
        } else {
            // So, browser is requesting the media. Return a real StreamedContent with the media bytes.
            String id = context.getExternalContext().getRequestParameterMap().get("id");
            Media media = service.find(Long.valueOf(id));
            return new DefaultStreamedContent(new ByteArrayInputStream(media.getBytes()));
        }
    }

}

这篇关于PrimeFaces p:media无法与@ViewScoped bean中的StreamedContent一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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