Template based web design with JSF Facelets: ui:insert versus ui:include
When creating a web page template with JSF, a developer needs to know the difference between ui:insert and ui:include. They're actually quite different, but the similar sounding names can create confusion. Here's a great example of when to use ui:insert and how to properly use ui:include.
In these tutorials on template based webpage development with JSF 2.x and Facelets, we've kept the basic layout page pretty simple. We have defined the various page elements with the ui:insert tag, and then within those tags, we've simply spit out a word like Heading or Footer or Messages, right there inside the layout.xhtml page itself. This is acceptable in a tutorial, but normally, each individual page element, be it the header, footer, right navigation pane and even the content window would normally go in a separate file. For example, anything to do with the footer should go in a file of its own, likely named footer.xhtml. Here is what the code would look like if we factored out the various page elements into their own files:
The footer.xhtml page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition> <p>Footer</p> </ui:composition> </h:body> </h:html>
The header.xhtml page:
<h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition> <p>Header</p> </ui:composition> </h:body> </h:html>
The messages.xhtml page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition> <p>Messages</p> </ui:composition> </h:body> </html>
The rightnav.xhtml page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition> <p>Sidebar/Right-nav</p> </ui:composition> </h:body> </html>
Take a look at the following screenshot of the page we are developing to get a better idea of where each of these code snippets will eventually land:
Template based design with JSF Facelets: The difference between ui:insert and ui:include
When the page is divided up into individual files, they can be aggregated into the template by using the ui:insert tag, not to be confused with the ui:include tag. Doing so, the corresponding entries in the previous iteration of the layout.xhtml will change from what is seen below:
<div id="header"> <ui:insert name="header"> <p>Header</p> </ui:insert> </div>
to what is seen here:
<div id="header"> <ui:insert name="header"> <ui:include src="header.xhtml" /> </ui:insert> </div>
Abstraction through the ui:include tag
Of course, using the ui:include tag adds an extra level of indirection to your template, but given the fact that headers and footers and other page elements in a typical enterprise application will be quite complex, factoring out this content into individual pages is a must.
When the layout.xhtml is completely refactored to use ui:includes rather than just hard coding information, the final product reads as follows:
<html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <link href="stylesheet.css" rel="stylesheet" type="text/css" /> </h:head> <h:body> <div id="page"> <div id="header-container"> <div id="header"> <ui:insert name="header"> <ui:include src="header.xhtml" /> </ui:insert> </div> </div> <div id="messages-container"> <div id="messages"> <ui:insert name="messages"> <ui:include src="messages.xhtml" /> </ui:insert> </div> </div> <div id="content-container"> <div id="content"> <ui:insert name="content"> Main content </ui:insert> </div> <div id="sidebar"> <ui:insert name="rightnav"> <ui:include src="rightnav.xhtml" /> </ui:insert> </div> </div> <div id="footer-container"> <div id="footer"> <ui:insert name="footer"> <ui:include src="footer.xhtml" /> </ui:insert> </div> </div> <div id="debug-container"> <div id="debug"> <ui:insert name="debug"> <ui:include src="debug.xhtml" /> </ui:insert> </div> </div> </div> </h:body> </html>
Further refactoring of the Facelets application
The use of includes can then be taken to the next level with the actual pages that use the template using ui:include calls as well. To do this you would put the content to be displayed in individual xhtml files. In this case, each file was placed under a subdirectory named content.
The pages in the \content folder simply contain the meaty information to be displayed by each page.
\content\01name.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition> <p>What is your name?</p> <p><a href="step02_birthday.xhtml">Next</a></p> </ui:composition> </h:body> </h:html>
\content\02birthday.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition> <p>What year were you born?</p> <p><a href="step03_completed.xhtml">Next</a></p> </ui:composition> </h:body> </h:html> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition> <p>Thanks you for the information.</p> </ui:composition> </h:body> </h:html>
\content\03summary.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition> <p>Thanks you for the information.</p> </ui:composition> </h:body> </h:html>
From there, each of the pages that extend the layout.xhtml template use the ui:include tag to reference the corresponding snippet.
step01_name.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition template="layout.xhtml"> <ui:define name="content"> <ui:include src="content/01name.xhtml" /> </ui:define> </ui:composition> </h:body> </h:html>
step02_birthday.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition template="layout.xhtml"> <ui:define name="content"> <ui:include src="content/02birthday.xhtml" /> </ui:define> </ui:composition> </h:body> </h:html>
step03_completed.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head></h:head> <h:body> <ui:composition template="layout.xhtml"> <ui:define name="content"> <ui:include src="content/03summary.xhtml" /> </ui:define> </ui:composition> </h:body> </h:html>
Here's how the three pages that comprise the final product look:
Conclusion
As you can see, there is a certain degree of indirection here which can make learning Facelets a little bit confusing. But that indirection becomes a godsend when creating complex applications, because complex logic can be factored out into individual files. In the end, the extra work and greater abstraction makes developing enterprise applications significantly easier.
What is your favorite Java based template engine? Let us know.
You can follow Cameron McKenzie on Twitter: @potemcam