我正在尝试显示在新浏览器窗口中打开的内联PDF . 我有以下场景:
-
在一些由ajax调用的ActionListen中,我生成PDF内容,将数据放入会话中,并发送Javascript来执行(
window.open
打开新页面以显示PDF) -
在打开的页面上,我只在
h:body
内有p:media
标签,其值指向StreamedContent
:
现在,在该页面上我的PDF不会生成 . 在日志中我可以看到这两行:
org.primefaces.application.PrimeResourceHandler handleResourceRequest
SEVERE: Error in streaming dynamic resource. Expression cannot be null
我开始调试并找出一些东西 .
首先,我将断点添加到 RequestScoped
bean的 @PostConstruct
方法中 . 有趣的是,断点达到了两次,并且在PDF显示完美之后让我大吃一惊?!
通过 PrimeResourceHandler
进行一些调试之后,我发现在某些情况下 ValueExpression
没有计算,实际上它会抛出 NullPointerException
,并且在调试时我再次看到发送了两个请求,第二个请求失败,因为在第一个请求中删除了 dynamicContentId
,并且第二次调用到 handleResourceRequest
没有意义 .
通过Firebug我可以看到两个请求,第一个是PDF数据,第二个也是内容类型application / pdf但是空,大小为0 .
xhtml页面:
<html>
<h:head></h:head>
<h:body>
<p:media value="#{reportBean.streamedContent}" player="pdf" width="500" height="500"/>
</h:body>
</html>
支持 beans :
@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 .
ADDED:
很容易重现我的问题 . 如果 init
方法中的代码替换为以下内容:
FileInputStream fis = new FileInputStream(new File("C:\\samplexxx.pdf"));
streamedContent = new DefaultStreamedContent(fis, "application/pdf");
问题可以再现 .
3 回答
我可以重现你的问题 . 它确实在Firefox中不起作用(也不适用于IE9,但它适用于Chrome) . PrimeFaces领导Cagatay也提到了several times .
我不确定这是PrimeFaces资源处理程序或浏览器中的错误 . 我会把它留在中间 .
与此同时,你最好的选择是工作的简单web servlet . 只需创建此类:
并按如下方式调用它:
而已 . 不需要XML配置 . 它适用于所有浏览器 . 根据功能要求,您可能希望进一步微调与浏览器缓存相关的响应标头 .
它不是一个浏览器或主要问题,只是一个有趣的getter问题 .
p:media会调用getter两次(或者如果刷新页面的次数多于此次),但只有第一次调用才能获得正确的数据 . StreamedContent封装了一个InputStream,它具有如果流位于文件末尾则不提供字节的属性 . 第一次读到它的结尾(数据没问题),但每次下一次调用都不会得到数据 . :)
javadoc of inputStream.read():如果没有字节可用,因为流位于文件的末尾,则返回值-1;否则,至少读取一个字节并存储到b中 .
Solution :
我希望我的小贡献可以帮助任何无法在Firefox中显示pdf预览的人 . 我使用的是Primefaces 6 Spring,我遇到了同样的问题,但也许并非由于同样的原因 . 实际上,我尝试了Balus C提出的解决方案 . 它帮助我在Chrome和IE11中显示pdf,但它仍然无法在Firefox 52中运行 .
我注意到Firefox控制台中出现错误:X-Frame-Options拒绝加载:http://localhost:8080/myapp/不允许框架
就我而言,这是因为spring-security配置和解决方案是以这种方式编辑spring-context.xml: