Facelets: entendiendo los templates de JSF

4
35485

En este tutorial vamos a ver los templates de JSF, cómo funcionan, cómo se crean y ejemplos prácticos de ello.

0. Índice de contenidos.

1. Por qué necesitaba una guía así.

En adictos ya existe un tutorial que explica las etiquetas para usar las Facelets de JSF 2. En esta entrada dejaré de lado la creación de componentes y explicaré únicamente el concepto de los templates y cómo se crean y usan.

Cuando comencé a aprender JSF y me topé con los templates tuve serios problemas para entender el concepto. Acababa de introducirme en AngularJS y tendía a relacionarlo inconscientemente con el routing y los partials de este framework, una idea completamente contraria. Durante las horas que tardé en formarme una idea, eché en falta que alguien me explicase qué es un template en JSF. Esta entrada es para explicar cómo considero que se puede entender mejor, por si a alguien le puede ser de ayuda en algún momento.

Sin entrar demasiado en detalles, y antes de seguir con el tutorial, comentaré la diferencia principal entre ambos. Podríamos decir que en JSF 2 un template es un fichero de tipo xhtml, que define zonas en las que vamos a insertar contenido desde la página principal. En AngularJS es esta página principal la que declara la zona que contendrá el contenido y en función de la url se llenará con un partial (el template) que corresponda. Hay un par de formas de simular el comportamiento del segundo con JSF 2, pero en principio la idea no es esa.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil Mac Book Pro 15″ (2,4 Ghz Intel Core i5, 8 GB DDR3)
  • Sistema Operativo: Mac OS X El Capitan
  • Entorno de desarrollo: Eclipse Java EE IDE, Mars Release (4.5.2)
  • Apache Maven 4.0.0
  • JSF 2.2

3. Qué es un template.

Antes de comentar cómo se usan, es necesaria una explicación de qué son los templates y para qué se usan. De ahora en adelante, y salvo que diga lo contrario, siempre hablaré de templates en el ámbito de JSF 2. Hay dos definiciones muy importantes para entender cómo funciona:

  • Template: fichero que define zonas de contenido dinámico a ocupar por quien lo utilice.
  • Cliente: fichero principal, que utilizará el template y especificará qué contenido va en cada zona. Al indicar una ruta en la url, es al cliente al que se accede.

Con esos dos conceptos no habré ayudado demasiado. Quizá sea mejor si vemos cómo se aplicaría en un entorno “real”. Si pensamos en una web estándar, la plantilla definirá la imagen corporativa (header, footer, menús, colocación de elementos…) y dejará un hueco en la parte central para cambiar el contenido en función de nuestras necesidades. Después, cada una de las páginas cliente concretas utilizarán esta plantilla y decidirán qué contenido va en el medio. El código común solo se escribe una vez, aunque se use muchas.

Dibujo explicativo del uso de un template.

4. Cómo se crea un template.

A lo largo de lo que resta de tutorial, recurriré al ejemplo que se introduce en el libro JavaServer Faces 2.0, The Complete Reference y lo expandiré para aplicarlo a todas las etiquetas que tenemos a nuestra disposición. El template será para nosotros una hoja de papel ya escrita, con una serie de agujeros que nos permiten ver lo que hay debajo. El cliente será otra hoja que pondremos debajo y del que solo veremos el contenido que no tape el template.

Dibujo explicativo de qué es un template.

Definir un template es realmente simple. Partiendo de un un xhtml ya formado, solo habrá que usar el par de etiquetas <ui:insert name=”nombre_del_hueco”></ui:insert> para definir los huecos que queramos. Entre ellas podremos poner un contenido por defecto que se mostrará en caso de que el cliente no especifique nada.

Dibujo explicativo de la creación de un template.

Este es el código para crear un template con todo el contenido accesorio en una página web, con un hueco para el contenido. Por motivos de espacio, y para no repetir 3 veces un código muy similar, no corresponde a la imagen anterior.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets">

<head>
	<title>Tutorial de Facelets en JSF 2</title>
</head>
<body&
	<!-- Menús, headers y todo lo que vaya antes del contenido -->
	<ui:insert name="contenido">
		Contenido por defecto para que no quede en blanco...    
	</ui:insert>
	<!-- Footer y otros componentes que vayan después del contenido -->
</body>
</html>

 

5. Usar los templates que hemos creado.

Sabemos cómo crear un template pero, ¿cómo podemos usarlo? Disponemos de otro par de etiquetas para rellenar los huecos declarados con <ui:insert>. Se trata de <ui:define name=”nombre_del_hueco”></ui:define>. En nuestra analogía sería equivalente a calcular la zona de la hoja cliente que deja visible un determinado hueco y escribir el contenido debajo. Entre las etiquetas de apertura y cierre se escribirá todo el contenido xhtml que deba renderizarse.

Pero <ui:define> no puede aparecer de forma independiente. Es necesario decir qué template usar, no solo el hueco. Disponemos de dos pares de etiquetas para lograr esto, con comportamientos ligeramente distintos entre sí.

5.1. Tapando todo el cliente.

La primera opción que tenemos es usar <ui:composition template=”ruta_relativa_template.xhtml”> </ui:composition>. Dentro de estas etiquetas escribiremos los <ui:define> correspondientes a los <ui:insert> del template. Es importante destacar que todo el contenido que no sea un <ui:define> válido se pasará por alto a la hora de mostrarlo al usuario.

El comportamiento especial de estas etiquetas es que a la hora de renderizar va a obviar por completo todo lo que se haya escrito fuera del par de apertura/cierre. Volviendo nuestro ejemplo, sería como usar un papel cliente que es más pequeño (o igual) que la plantilla que ponemos encima. Es decir, la hoja template que hay arriba taparía por completo todo escrito en el cliente, excepto lo que se pueda leer por los recortes.

Dibujo explicativo del uso de la etiqueta composition.

En este dibujo ya hemos visto dónde se ubican exactamente los <ui:define> dentro de la hoja del cliente. A continuación lo veremos en un pequeño ejemplo para usar el template que creamos con el código del apartado anterior:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets">
 
<body>       
	<!-- Lo que escribamos aquí NO aquí se va a renderizar. -->
	Esto seguro que no lo ves.
	
	<ui:composition template="template.xhtml">
		<ui:define name="contenido">
			<h1>Contenido que inserta el cliente en el template.</h1>
		</ui:define>
	</ui:composition>
	
	<!-- Ni TAMPOCO esto. -->
	Y esto tampoco.
</body>
</html>

 

5.2. Viendo contenido propio del cliente fuera de la plantilla.

La segunda opción es usar las etiquetas <ui:decorate template=”ruta_relativa_template.xhtml”> </ui:decorate>, que se usan exactamente igual que las anteriores. La diferencia está en que esta vez sí se renderizará lo que hay alrededor del uso del template. El nombre lo deja claro, decora la plantilla con lo que hemos escrito en la página.

Aplicado a nuestro ejemplo, es como si el papel cliente fuese de un tamaño mayor al de la plantilla. Todo lo que esté escrito fuera de la zona que tapa la hoja superior se podrá ver perfectamente.

Dibujo explicativo del uso de la etiqueta decorate.

Aquí tenemos un código de ejemplo para consumir el template que habíamos creado anteriormente, esta vez añadiendo una imagen de cabecera y un footer para el copyright:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets">
 
<body>       
	<!-- Lo que escribamos aquí SI aquí se va a renderizar. -->
	<b>Aquí iría la imagen para la cabecera.</b>
	
	<ui:decorate template="template.xhtml">
		<ui:define name="contenido">
			<h1>Contenido que inserta el cliente en el template.</h1>
		</ui:define>
	</ui:decorate>
	
	<!-- Y esto TAMBIÉN. -->
	<b>Y aquí todo el contenido para el copyright.</b>
</body>
</html>

 

6. Insertar fichero externo íntegro dentro de nuestra página.

Aunque no haga uso de los templates que hemos generado hasta ahora, los Facelets nos ofrecen otro par de etiquetas con un efecto relacionado. Al usar <ui:include src=””ruta_relativa_del_fichero.xhtml> </ui:include> podemos insertar el contenido íntegro de otro fichero xhtml en el punto donde se utiliza. Podríamos decir que es como si cortásemos el papel cliente en ese punto y pegásemos otra hoja con más contenido entre las dos partes.

Dibujo explicativo de la inclusión de contenido sin plantillas.

Además podemos utilizar dentro del <ui:include> la etiqueta <ui:param name=”nombre_parametro” value=”valor”> para pasarle parámetros al fichero incluido. Para usarlos se hará con la sintaxis #{nombre_parametro}.

Aquí podemos ver un pequeño ejemplo de estas dos etiquetas. Por un lado tenemos el xhtml que vamos a incluir y en el que usamos el parámetro name:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
	Este es el contenido que hemos pegado en nuestra página <b>#{name}</b>.
</body>
</html>

Y por otro el código del xhtml que incluirá ese contenido y le pasará el parámetro:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
	<title>Tutorial de Facelets en JSF 2</title>
</head>
<body>       
	<!-- Lo que escribamos aquí SI aquí se va a renderizar. -->	
	<ui:include src="toInclude.xhtml">
		<ui:param name="name" value="cliente"></ui:param>
	</ui:include>
	<!-- Y esto TAMBIÉN. -->
</body>
</html>

A modo de curiosidad, utilizar un <ui:decorator> sin ningún <ui:define> válido es equivalente a un <ui:include> sin parámetros. Ambos insertan el contenido del fichero objetivo en el punto de uso de las etiquetas. De todos modos, aunque tengamos esta posibilidad siempre deberemos usar el segundo método cuando necesitemos incluir contenido externo. Tengamos claro en todo momento el objetivo de uso de los templates.

6.1. Simular el comportamiento de los templates de AngularJS con JSF 2.

En AngularJS se utiliza la etiqueta <ng-view> para declarar una zona de la página donde insertaremos el contenido de otro html. Haremos uso del servicio $route (en el módulo ngRoute) para especificar el fichero concreto que se cargará en función de la url a la que se acceda.

Simular este comportamiento con JSF 2 es muy sencillo. La inclusión del contenido de ficheros externos se puede hacer con el <ui:incude> que acabamos de ver. Para el enrutamiento podríamos declarar un solo cliente y utilizar los ViewParams para especificar en la propia url cuál es el fichero a incluir en él. No es el objeto de esta entrada explicar los ViewParams, así que nos quedaremos aquí.
Siempre que podamos, deberíamos utilizar los recursos que pone a nuestra disposición JSF 2 para escribir aplicaciones de la forma más simple que podamos. Esta última sección solo está para situar el modus operandi de Angular JS dentro del ecosistema de JSF y así poder entender mejor este último si, como yo, venías de ahí. No pretendo aconsejar el uso de una implementación a todas luces retorcida.

7. Código del tutorial.

En mi repositorio de GitHub podéis encontrar un proyecto con todo el código escrito usado a lo largo del tutorial. Para ejecutarlo solo hay que importarlo y desplegarlo en un servidor de aplicaciones a elección. Para navegar por las diferentes páginas clientes solo debemos añadir su nombre al final de la url principal. Aunque también se puede editar el welcome-file en el /src/main/webapp/WEB-INF/web.xml.

8. Conclusiones.

En esta entrada solo he explicado la punta del iceberg en lo relativo al uso de templates con JSF 2. Son una herramienta muy potente para favorecer la reutilización de código en nuestros proyectos web. Además, se pueden llegar a combinar y utilizar templates unos dentro de otros, compartir <ui:insert> entre varios para meterles contenido de una sola vez, declararlos en el <head> del xhtml en lugar de en el <body>, etc. Con las bases dadas en este tutorial se pueden crear páginas muy completas y es dificil que para uso diario se necesite algo más. No obstante, os animo a experimentar para lograr soluciones más complejas a vuestros problemas.

9. Reconocimientos.

Para la creación de mis imágenes he utilizado los siguientes iconos de The Noun Project:

  • Scissors by Boudewijn Mijnlieff from the Noun Project
  • Masking tape by hatayas from the Noun Project

4 COMENTARIOS

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad