我正在使用Liferay portlet,它使用PrimeFaces 5作为其UI。典型的请求呈现一些XHTML模板并将生成的HTML发送到客户端。我想在commandButton动作处理程序的上下文中将我选择的XHTML文件呈现为字符串。
为了说明我的目的,假设我有以下commandButton定义:
<h:form>
<p:commandButton value="Export as PDF" ajax="false" action="#{myBean.exportPDF}" />
</h:form>
单击时,它将执行辅助bean的exportPDF方法。在该方法中,我将另一个xhtml文件的内容加载到字符串中。这部分已经完成并且有效。现在,我猜我需要将字符串解析为UIComponent层次结构,然后使用当前的FacesContext呈现该层次结构。这就是我目前陷入困境的地方。
FacesContext具有{get,set} ViewRoot方法。当前视图根是客户端在其浏览器中看到的内容。如何将此视图根替换为从任意字符串生成的视图?
如按钮名称所示,所需的操作是向客户端发送PDF。我得到HttpServletResponse实例,输出正确的标题,并生成实际的PDF内容。我正在使用Flying Saucer进行PDF生成,我基本上是尝试从JSF模板创建输入XHTML。除模板位外,一切都已经有效。相关代码如下:
public void exportPDF() throws DocumentException, IOException {
FacesContext ctx = FacesContext.getCurrentInstance();
ByteArrayOutputStream buf = new ByteArrayOutputStream();
ITextRenderer r = new ITextRenderer();
r.setDocumentFromString(getExportXHTML(ctx));
r.layout();
r.createPDF(buf);
HttpServletResponse sr = PortalUtil.getHttpServletResponse(
(PortletResponse)ctx.getExternalContext().getResponse());
sendPDF(sr, buf);
ctx.responseComplete();
}
private String getExportXHTML(FacesContext ctx) throws IOException {
StringBuilder s = new StringBuilder(4096);
PortletRequest pr = (PortletRequest)ctx.getExternalContext().getRequest();
PortletContext pc = pr.getPortletSession().getPortletContext();
InputStream is = pc.getResourceAsStream("/views/pdf.xhtml");
try {
InputStreamReader r = new InputStreamReader(is, "utf-8");
char[] buf = new char[4096];
int n;
while ((n = r.read(buf)) != -1) {
s.append(buf, 0, n);
}
} finally {
is.close();
}
String template = s.toString();
return ??? // TODO: How do I render template with ctx?
}
解决
找到以下链接,这些链接让我非常接近工作解决方案:
唯一剩下的问题是我无法在动作处理程序中渲染任何内容。 ctx.getExternalContext()。getResponse()返回一个ActionResponse实例,而不是渲染所需的MimeResponse。为了解决这个问题,我在初始页面加载期间简单地渲染了XHTML,但是在将XHTML转换为PDF之前等待动作处理程序被调用。如果用户不想要PDF,效率会有点低,但看起来效果不错。