我想在JSF2的新页面中打开PDF,并在加载时在此pdf中显示某个页面。我的jsf页面中有一种TOC,想直接从那里跳到PDF中的页面。
我所知道的(这不是,我需要的,只是给adobe reader和其他pdf阅读器提供我要跳转到的页面的一个例子): 这样的东西会打开页面(从互联网上选择一些东西): https://www.cdc.gov/diabetes/pdfs/data/statistics/national-diabetes-statistics-report.pdf#page=10
#page = 10使浏览器显示页面10的pdf插件。
选择PDF的要求:
现在我真正的问题:我必须更改在JSF中显示/使用的URL,但不能使用和includeViewParams一样的正常方式,因为这将插入"?",而不是"#"在网址中。
另外,我有一个支持bean,它根据我给出的其他一些参数从后端服务获取PDF的内容,所以解决方案很酷,但我知道这可能是不可能的......
有没有人有想法,如何解决这个问题? 我没有包含任何代码,因为它无论如何都不起作用,而且我可能需要一种全新的方法来解决这个问题......
答案 0 :(得分:0)
事实证明,Primefaces已经实现了这一点(虽然实现有它的限制):
<p:media player="pdf" value="#{viewerBean.media}" width="100%" height="100%">
<f:param name="#page" value="#{viewerBean.pageNumber}"/>
<f:param name="toolbar" value="1"/>
<!--<f:param name="search" value="#{viewerBean.queryText}"/>-->
</p:media>
https://www.primefaces.org/showcase/ui/multimedia/media.xhtml
限制:无法从流中读取,至少不是很稳定。节省能源,并将流写入临时文件,并动态设置此文件名。不确定,这是否完整,但你应该明白:
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import java.io.*;
import javax.annotation.PostConstruct;
import java.nio.file.Files;
import java.nio.file.Paths;
@ManagedBean
@RequestScoped
public class ViewerBean implements Serializable {
@ManagedProperty(value = "#{param.page}")
private String pageNumber;
private File media;
@PostConstruct
public void init() {
try {
media = Files.createTempFile("car", ".pdf").toFile();
try (FileOutputStream outputStream = new FileOutputStream(media)) {
IOUtils.copy(getStreamedContent().getStream(), outputStream);
}
} catch (IOException e) {
LOGGER.error(e);
throw new RuntimeException("Error creating temp file", e);
}
}
public StreamedContent getMedia() {
try {
return new DefaultStreamedContent(new FileInputStream(media), "application/pdf");
} catch (FileNotFoundException e) {
String message = "Error reading file " + media.getAbsolutePath();
LOGGER.error(message, e);
throw new RuntimeException(message, e);
}
}
}
如果不需要页面名称,您可以使用: http://balusc.omnifaces.org/2006/05/pdf-handling.html
也许如果你可以使用outputLink,你会很幸运,但我没时间测试这个选项。
答案 1 :(得分:0)
找到(THE)解决方案;以上回答提及,但这不能处理@ViewScope
bean,并向底层bean发送许多请求,只读取一个InputStream。我发现由于负载原因这是不可接受的。
所以我们走了:
<f:event type="preRenderView" listener="#{documentDownloadBean.writeIntpuStreamToResponseOutputStream}"/>
重定向到上面的JSF页面,如:return "document_search/view_pdf.xhtml?faces-redirect=true#page=" + page;
@ManagedBean
@ViewScoped
public class DocumentDownloadBean implements Serializable {
@ManagedProperty(value = "#{documentSearchBean}")
private DocumentSearchBean documentSearchBean;
public String activeDocumentToFlashScope(String page) {
Document document = documentSearchBean.getSelectedDocument();
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("document", document);
// everything preapared now, redirect to viewing JSF page, with page=xxx parameter in URL, which will be evaluated by adobe pdf reader (and other readers, too)
return "document_search/view_pdf.xhtml?faces-redirect=true#page=" + page;
}
public void download() {
Document document = (Document) FacesContext.getCurrentInstance().getExternalContext().getFlash().get("document");
InputStream inputStream = getInputstreamFromBackingWebserviceSomehow(document);
FacesUtils.writeToResponseStream(FacesContext.getCurrentInstance().getExternalContext(), inputStream, document.getFileName());
}
}
调用JSF页面:
<p:commandLink id="outputText" action="#{documentDownloadBean.activeDocumentToFlashScope(selectedDocument, page)}"
target="_blank" ajax="false">
<h:outputText value="View PDF"/>
</p:commandLink>