Ejemplo de plantillas en JavaServer Faces (JSF 2.0)

Usar plantillas (Templates) en JSF es muy sencillo, y el uso de platillas nos evita tener código duplicado en múltiples páginas puesto que normalmente las distintas páginas de la aplicación tendrán un estilo común y algunos elementos como la cabecera, el pie de pagina o el menú en muchas ocasiones se mantendrán estáticos por lo que usando plantillas solo tendremos que definir dichos elementos una sola vez y para cada nueva pagina solo habrá que crear el contenido propio de dicha pagina y así se consigue tener una web más fácil de mantener.

Crear una plantilla

En JavaServer Faces hacer una plantilla no tiene ningún misterio ya que será un facelet normal y corriente con la única particularidad de que donde queramos introducir una parte modificable de la plantilla habrá que introducir el tag <ui:insert name=»nombre»> y dentro de esta etiqueta podremos poner el código que queremos que aparezca si no se quiere sobrescribir si tiene sentido hacer tal cosa.

Un ejemplo de plantilla podría ser el siguiente donde se puede modificar el contenido de la etiqueta title, el titulo de la página y como no podía ser de otra forma el contenido, mientras que la barra de navegación y el pie de página siempre permanecerán inalterables.


<?xml version='1.0' encoding='UTF-8' ?> 
<!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:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">

    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link href="./../resources/css/estilo.css" rel="stylesheet" type="text/css" />
        <title>
            <ui:insert name="titulo">
                Facelets Template
            </ui:insert>
        </title>
    </h:head>

    <h:body>

        <header id="cabecera">
            <ui:insert name="cabecera">
                <h1>Plantillas JSF</h1>
            </ui:insert>
        </header>

        <div class="cuerpo">
            <nav id="menu">
                <h:form>
                    <ul>
                        <li><h:commandLink action="inicio">Inicio</h:commandLink></li>
                        <li><h:commandLink action="productos">Productos</h:commandLink></li>
                        <li><h:commandLink action="localizacion">Localización</h:commandLink></li>
                        <li><h:commandLink action="contacto">Contacto</h:commandLink></li>
                    </ul> 
                </h:form>
            </nav>

            <article class="contenido">
                <ui:insert name="contenido">
                    Aqui va el contenido de la página
                </ui:insert>
            </article>
        </div>

        <footer id="pie">
            <span id="proyecto">Ejemplo uso de plantillas JSF.</span>
            <span id="autor"><a href="http:programandoointentandolo.com">Iván Salas Corrales</a></span>
        </footer>

    </h:body>

</html>

Usar una plantilla

Si crear una plantilla es sencillo, pues implementar una plantilla como no podía ser de otro modo también es una tarea simple.

Vamos a ver un ejemplo de uso de la plantilla anterior:


<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
                template="./plantillas/plantilla.xhtml">
    
    <ui:define name="titulo">
        Productos
    </ui:define>

    <ui:define name="cabecera">
        <h1>Productos</h1>
    </ui:define>

    <ui:define name="contenido">
        Aquí van los productos
    </ui:define>

</ui:composition>

Como se puede ver para hacer uso de una plantilla necesitamos incluir el tag <ui:composition> e indicar en su atributo template la ruta en la que se encuentra la plantilla. Y ya solo nos queda definir las partes que queremos modificar mediante <ui:define> indicando en el atributo name el nombre de la parte que se quiere modificar pudiendo incluir lo que queramos.

Aunque en el ejemplo anterior hemos redefinido todos las partes que había definidas en la plantilla esto no tiene por qué ser así y podríamos poner solo la parte o partes que nos interesen como en el ejemplo siguiente donde solo esta modificado el contenido.


<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
                template="./plantillas/plantilla.xhtml">
    
    <ui:define name="contenido">
        Pagina de inicio de la aplicación
    </ui:define>

</ui:composition>

Reglas de navegación globales

Aunque las reglas de navegación son independientes del uso de plantillas, cuando se usan plantillas el menú suele permanecer constante o al menos una parte de el por lo que normalmente haremos uso de reglas de navegación globales para no tener que replicar el código por cada nueva pagina y lo único que se necesita hacer es definir una regla de navegación y en lugar de poner en <from-view-id> el nombre de la vista a la que pertenecerán esas reglas de navegación poner un asterisco y de esta forma esta navigation-rule funcionará con cualquier página de la aplicación.


<faces-config version="2.0"
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">

    <navigation-rule>
        <from-view-id>*</from-view-id>
        <navigation-case>
            <from-outcome>inicio</from-outcome>
            <to-view-id>/index.xhtml</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-outcome>productos</from-outcome>
            <to-view-id>/productos.xhtml</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-outcome>localizacion</from-outcome>
            <to-view-id>/localizacion.xhtml</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-outcome>contacto</from-outcome>
            <to-view-id>/contacto.xhtml</to-view-id>
        </navigation-case>
    </navigation-rule>
    
    <navigation-rule>
        <from-view-id>/localizacion.xhtml</from-view-id>
        <navigation-case>
            <from-outcome>inicio</from-outcome>
            <to-view-id>/productos.xhtml</to-view-id>
        </navigation-case>
    </navigation-rule>
</faces-config>

En el faces-config.xml anterior además de la regla de navegación global hay definida otra regla solo para la vista /localizacion.xhtml y el caso de navegación coincide con uno de los de la regla de navegación global aunque el destino es distinto, y aunque no tiene sentido esta nueva regla de navegación porque ya la teníamos en el caso global y además el nombre puede crear confusión, el motivo de ponerlo no es otro que comprobar que siempre se ejecutan primero las reglas de navegación más especificas, por lo que en este caso si usásemos el enlace inicio en /localizacion.xhtml no se nos mandaría a inicio sino a productos.

Y esto es lo único que hay que saber para poder usar plantillas en Java Server Faces, y como siempre el código completo del ejemplo lo puedes descargar aquí.