Plantillas en JSF 2.0

En esta tercera entrega dedicada a JSF voy introducir el uso de plantillas. Existen muchas razones para implementar su uso: hacer más sencillo el diseño de los xhtml, eliminar código redundante y relacionado con este último mantener un interfaz homogeneo en toda la aplicación. La única razón que se me ocurre para no emplearlo es no conocer su existencia o no saber implementarlo.
Si conoces otros entornos puedes ver el paralelismo con sitemesh o  los tiles tan comunes en struts2.
La idea principal es definir una página base y que el resto de las páginas se encajen en esa. Ejemplo tipico es el portal que mantiene a lo largo de todas las páginas una cabecera y un menú.común o una cabecera, debajo un menú de navegación y un menú en función de la zona de navagación seleccionada.
En el ejemplo desarrollado hasta ahora se puede observar un montón de código común, que es candidato idoneo para sacarlo a la plantilla.  Veremos cómo dentro de un momento.
Vamos a empezar por dotar de algo más de lógica a la aplicación, creando un menú con una opción para ir a la pantalla de login y que una vez logueado nos muestre un menú ampliado.
Para ello en la carpeta webapp de nuestro proyecto eclipse vamos a crear una carpeta resources y en ella vamos a meter, la plantilla base y unas hojas de estilo muy básicas, así vamos mejorando un poco la presentación. En la plantilla base vamos a definir tres zonas: cabecera, menú y contenido (top, left y content) y en nuestro desarrollo sólo tendremos que preocuparnos del "content".Además de la plantilla vamos a definir  la zona de menú, y la zona de cabecera, crearemos una nueva págiuna de inicio, "home.xhtml" y la definiremos como tal en el web.xml. El menú y la cabecera son también  archivos "xhtml".
La plantilla base, "base.xhtml":

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<f:loadBundle basename="messages" var="msg" />
<h:head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link href="./resources/default.css" rel="stylesheet" type="text/css" />
    <link href="./resources/cssLayout.css" rel="stylesheet" type="text/css" />
    <title>#{msg.mainTittle}</title>
</h:head>

<h:body>
    <div id="top" class="top">
        <ui:insert name="top">cabecera</ui:insert>
    </div>
    <div>
        <div id="left">
            <ui:insert name="left">menu</ui:insert>
        </div>
        <div id="content">
            <ui:insert name="content">contenido</ui:insert>
        </div>
    </div>
</h:body>
</html>


 Destacar que metemos en la plantilla la carga del bundle que nos da soporte a la internacionalización para no tener que repetirlo u olvidarlo en todas y cada una de las páginas. Y que añadimos el soporte para etiquetas "ui".

La cabecera la metemos en el : "header.xhtml"

!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:body>
    <ui:composition>
        <h1>#{msg.headerTittle}</h1>
    </ui:composition>
</h:body>
</html>


De todo el código de esta página en el momento del renderizado insertará lo que va dentro de la etiqueta
<ui:composition>.

El menú chequeará si hay un usuario logueado, si lo está muestra un menú, si no lo está muestra un menú con un único botón para loguearse:
    <ui:composition>
        <h:form rendered="#{!empty user.name}">
            <h:panelGrid columns="1" width="60">
                <h:commandButton value="#{msg.loginOut}" action="#{login.clearUser}"/>
                <h:commandButton value="#{msg.loginFoo}" action="#{login.clearUser}"/>
            </h:panelGrid>
        </h:form>

        <h:form rendered="#{empty user.name}">
            <h:panelGrid columns="1" width="60">
                <h:commandButton value="#{msg.loginIn}" action="login"/>
            </h:panelGrid>
        </h:form>
    </ui:composition>


En la clase login definimos un método que nos "desloguea" poniendo el "user.name" a null y utilizamos EL (Expresion Languaje) para controlar qué formulario debe aparecer.

La página de inicio "home" tiene que tomar la plantilla e "inyectarle" la cabecera, el menú y mostrar su propio contenido:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:body>
    <ui:composition template="/resources/base.xhtml">
        <ui:define name="top">
            <ui:include src="/resources/header.xhtml"/>
        </ui:define>
        <ui:define name="left">
            <ui:include src="/resources/menu.xhtml"/>
        </ui:define>
        <ui:define name="content">
                #{msg.loginWelcome}
            </ui:define>
    </ui:composition>
</h:body>
</html>

Lo único que tiene que hacer es indicar para cada una de las partes de la plantilla qué es lo que hay que poner en ella.

Una vez que estamos logueados vamos a la pantalla de loginOk que queda así:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:body>
    <ui:composition template="/resources/base.xhtml">
        <ui:define name="top">
            <ui:include src="/resources/header.xhtml" />
        </ui:define>
        <ui:define name="left">
            <ui:include src="/resources/menu.xhtml" />
        </ui:define>
        <ui:define name="content">
            <h:outputFormat value="#{msg.loginOkWelcome}">
                <f:param value="#{user.name}" />
            </h:outputFormat>
        </ui:define>
    </ui:composition>
</h:body>
</html>


Creo que aparte de las hojas de estilo y el archivo de literales, esto son todos los cambios importantes..Archivo de literales, una hoja de estilo y la otra hoja de estilo.

El proyecto completo se puede descargar desde aquí.