PrimeFaces p:media 不能在 @ViewScoped bean 中使用 StreamedContent [英] PrimeFaces p:media not working with StreamedContent in a @ViewScoped bean

查看:20
本文介绍了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.

相关代码如下:

后豆:

@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.

推荐答案

您的具体问题是因为网络浏览器实际上是在物理上完全独立的 HTTP 请求中下载 PDF 文件,而不是生成和发送 HTML 输出的 HTTP 请求基于 JSF 源代码.您可能已经知道视图范围 bean 通过 javax.faces.ViewState 隐藏输入字段绑定到特定的 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 的这个问题与 的问题具有基本相同的理由和 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:

在您的特定情况下,您需要以这样的方式重新设计整个文件:DocumentsBean 支持 bean 通过以下方式将 PDF 文件存储在某个地方(例如临时磁盘、服务器内存、数据库等)一个唯一标识符,然后将该唯一标识符作为请求参数传递给 ,如下所示:

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天全站免登陆