Con*_*ang 3 media pdf jsf primefaces view-scope
我有一个与浏览器中的Primefaces4 meida类型渲染pdf文件有关的问题.我已经成功地尝试了来自primefaces网站的展示示例.现在我想获得一个新功能,它在左侧面板中提供了一个带有文档节点的树结构.用户可以选择一个文档在中心面板中显示它.这意味着一旦用户选择了树上的一个文档,它就会在backbean中生成pdf媒体字段.
相关代码如下所示:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
我的观点的一部分:
<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>
Run Code Online (Sandbox Code Playgroud)
当我运行此代码时,没有错误或异常.但是,Firefox中没有生成PDF查看器.真奇怪!
基于BalusC评论的后续问题:
我的应用程序运行时出现此异常:
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)
Run Code Online (Sandbox Code Playgroud)
我发现这行导致了这个异常:
return new DefaultStreamedContent();
Run Code Online (Sandbox Code Playgroud)
如果我创建一个真正的pdf文件,异常就消失了.但是如果用户没有选择该文件,我真的不希望显示pdf文件.
您的具体问题是由于Web浏览器实际上是在物理上完全独立的HTTP请求中下载PDF文件,而不是基于JSF源代码生成和发送HTML输出的HTTP请求.您可能已经知道视图作用域bean通过javax.faces.ViewState隐藏的输入字段绑定到特定的JSF视图.如果这个被更改或不存在,那么请求将获得一个新的,不同的视图范围bean实例.
换句话说,当浏览器在单独的HTTP请求中从服务器下载PDF文件时,它不使用相同的@ViewScopedbean实例,而是获得一个全新且完全独立的实例,该实例不具有相同的属性(状态)作为一个绑在页面上的那个,因此整个StreamedContent就是null那个时候.
这个问题<p:media>,并StreamedContent具有基本相同的理由与问题<p:graphicImage>和StreamedContent其回答前几次:
在您的特定情况下,您需要重新设计整个群集,以便DocumentsBean支持bean通过唯一标识符将PDF文件存储在某个位置(例如临时磁盘,服务器内存,数据库等),然后准确传递该唯一标识符作为请求参数<p:media>如下:
<p:media value="#{mediaManager.stream}" width="100%" height="700px" player="pdf">
<f:param name="id" value="#{documentsBean.mediaId}" />
</p:media>
Run Code Online (Sandbox Code Playgroud)
因此,MediaManager支持bean看起来像这样:
@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()));
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8569 次 |
| 最近记录: |