Render JavaServer Faces xhtml for string on server
I am working with a Liferay portlet that uses PrimeFaces 5 for its user interface. A typical request renders some XHTML template and sends the resulting HTML to the client. I would like to display an XHTML file of my choice for a line in the context of a commandButton action handler.
To illustrate what I need, suppose I have the following commandButton definition:
<h:form>
<p:commandButton value="Export as PDF" ajax="false" action="#{myBean.exportPDF}" />
</h:form>
Clicking on it executes the exportPDF method to support the bean. Inside this method, I am loading the content of another xhtml file into a string. This part is done and working. Now my guess is that I need to parse a string in the UIComponent hierarchy and then display that hierarchy using the current FacesContext. This is where I am now stuck.
The FacesContext has {get, set} ViewRoot methods. The current view root is what the client sees in their browser. How can I replace this view root with one generated from an arbitrary string?
As the name of the button suggests, the desired action is to send a PDF to the client. I am getting an HttpServletResponse instance, outputting the correct headers and generating the actual PDF content. I am using Flying Saucer to generate PDF and I am basically trying to generate input XHTML from JSF template. Everything already works except for the template bits. Relevant code below:
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?
}
solved
Found the following links that brought me closer to a working solution:
- http://www.ninthavenue.com.au/how-to-create-email-from-jsf-templates
- https://github.com/vvasabi/Programmatic-Facelets-Rendering-Example
The only remaining problem was that I couldn't do anything in the action handler. ctx.getExternalContext (). getResponse () returned an ActionResponse instance, not a MimeResponse required for rendering. To get around this, I just rendered the XHTML during initial page load, but waited for the action handler to be called before converting the XHTML to PDF. A bit ineffective if the user doesn't want the PDF, but seems to work otherwise.
source to share
No one has answered this question yet
Check out similar questions: