8. Facelets, JSTL y lenguajes de expresiones
8.1. JavaServer Faces y Facelets
JavaServer Faces (JSF) es un framework para la creación de aplicaciones web en el lado del servidor. Dentro de este framework encontramos:
-
Una API que nos proporciona componentes que podemos utilizar en la interfaz de nuestra aplicación y nos permite gestionar sus eventos y su validación en el lado del servidor. Ejemplos de componentes son los botones, cuadros de texto, imágenes, mensajes de texto, etc.
-
Librerías de etiquetas con las que podemos añadir los componentes anteriores a una página web sin necesidad de introducir código Java. Por ejemplo, encontramos etiquetas como
<h:form>
,<h:inputText>
,<h:graphicImage>
,<h:selectOneMenu>
, etc.
Una página JSF se representa mediante un árbol de componentes, al que se llama vista.
Los componentes que constituyen la vista son elementos reutilizables y configurables como por ejemplo botones, campos de texto, tablas, etc. Todos los componentes se implementan en clases que heredan de UIComponentBase
. Estas clases implementan la funcionalidad del componente, pero no la forma de mostrarlo. Esta separación permite crear de forma sencilla varias formas de mostrar un componente reutilizando su funcionalidad. La forma de mostrar un componente se implementa mediante un objeto de tipo Renderer
.
Podemos tener diferentes etiquetas para un mismo componente, de manera que cada una de ellas lo muestre de forma distinta. Por ejemplo, el componente UISelectOne
tiene la funcionalidad de permitir seleccionar un único elemento de una lista, pero puede presentarse mediante tres renderers alternativos, por lo que tenemos disponibles tres etiquetas para este mismo componente:
-
<h:selectOneListbox>
: Se muestra como un cuadro de lista donde aparecen todas las opciones. -
<h:selectOneMenu>
: Se muestra como un menú desplegable. -
<h:selectOneRadio>
: Se muestra como botones de radio.
Cada etiqueta de la librería HTML de JSF relaciona un componente con un renderer determinado para mostrarlo.
Una ventaja de JSF es que separa claramente la presentación de la lógica. Existen diferentes opciones para crear la vista en JSF. Se podría utilizar cualquier tipo de componente en el que podamos incluir las etiquetas que proporciona, como son por ejemplo los JSPs, pero la opción recomendada es la tecnología de Facelets. Vamos a centrarnos en estudiar los Facelets y los distintos elementos que podemos incluir en ellos.
8.2. Introducción a los Facelets
Los Facelets consisten en páginas creadas en XHTML, dentro de las cuales podemos utilizar los siguientes elementos:
-
Librerías de tags de Facelets, JSF y JSTL: Se utilizan fundamentalmente para crear los diferentes componentes de la interfaz de la página, además de especificar la forma de validarlos o de presentar los datos.
-
Lenguaje de expresiones (EL): Nos permite relacionar los componentes anteriores con datos de nuestra aplicación, como por ejemplo aquellos contenidos en managed beans, o aquellos que recibimos como parámetros de la petición. Podremos utilizar este lenguaje en el cuerpo de la página o en los atributos de las etiquetas anteriores para consultar o guardar datos en managed beans, realizar operaciones con ellos, etc.
-
Plantillas de componentes y páginas: Podemos definir la estructura de contenido de nuestras páginas mediante una plantilla, y aplicar esta plantilla a todas ellas. Por ejemplo podremos definir en la plantilla bloques para la cabecera, pie, menú lateral, etc.
En los siguientes apartados estudiaremos con detalle cada uno de los componentes anteriores.
Para crear una aplicación que utilice Facelets deberemos realizar lo siguiente:
-
Mapear el servet de JSF (
FacesServlet
) a un determinado patrón de URL (por ejemplo*.xhtml
). -
Crear managed beans. Desde los Facelets accederemos a los datos de nuestra aplicación a través de ellos.
-
Crear páginas utilizando las etiquetas de componentes. Los Facelets serán estas página XHTML que utilizarán dichas etiquetas y accederán a los datos mediante managed beans.
8.2.1. Mapeo del servlet de JSF
Para poder usar Facelets deberemos mapear el servlet de JSF a un determinado patrón de URL para que se encargue de procesar todas las páginas que se ajusten a dicho patrón. Normalmente quedará mapeado al patrón *.xhtml
, para que todas las páginas que tengan dicha extensión sean procesadas como Facelets. De no añadir este mapeo se tratarían como páginas estáticas.
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
Esto puede hacerse de forma automática desde IntelliJ. Bastará con situarse sobre el directorio WEB-INF , pulsar con el botón derecho y seleccionar New > XML Configuration File > Faces Config. Con esto se creará en WEB-INF en fichero de configuración de JSF (faces-config.xml ), y añadirá al descriptor de despliegue la configuración del Faces Servlet que se encargará de procesar los Facelets.
|

8.2.2. Estructura básica de un Facelet
A continuación mostramos la estructura básica que tiene un Facelet:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"> (1)
<h:head> (2)
<title>Mi primer Facelet</title>
</h:head>
<h:body> (3)
<!-- Contenido de la página -->
</h:body>
</html>
1 | Declaración de las librerías de etiquetas a utilizar. En este caso declaramos únicamente la librería HTML de JSF asignándole el prefijo h . |
2 | En lugar de <head> se suele utilizar una etiqueta equivalente de la librería HTML de JSP. Al haber sido declarada con prefijo h , dicha etiqueta será <h:head> . |
3 | Al igual que <head> , para la etiqueta <body> también utilizamos la etiqueta equivalente de JSF. |
Podemos crear un Facelet desde IntelliJ pulsando con el botón derecho sobre el directorio donde lo queramos añadir (por ejemplo webapp ) y seleccionando New > JSF/Facelets.
|

8.2.3. Declaración de librerías de etiquetas
En el ejemplo anterior hemos declarado únicamente la librería HTML de JSF. Podríamos añadir a la declaración otras librerías de etiquetas como por ejemplo las que se muestran a continución:
Librería | URI | Prefijo | Descripción |
---|---|---|---|
JSF HTML Tag Library |
h |
Componentes de la UI de la página |
|
JSF Core Tag Library |
f |
Funciones y acciones |
|
JSTL Core Tag Library |
c |
Etiquetas de propósito general de JSTL |
|
JSTL Functions Tag Library |
fn |
Funciones de JSTL |
Cada librería tiene un prefijo definido por convención que utilizaremos normalmente al declararla, pero podríamos cambiarlo. Por ejemplo
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
En este caso hemos declarado la librería HTML de JSF con prefijo h
y la librería Core de JSTL con prefijo c
. Podríamos también declararlas de la siguiente forma:
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:html="http://xmlns.jcp.org/jsf/html"
xmlns:core="http://xmlns.jcp.org/jsp/jstl/core">
En este último caso las etiquetas de la librería HTML de JSF se escribirían con prefijo html
, como por ejemplo <html:head>
y <html:body>
. De la misma forma, las etiquetas de la librería Core de JSTL se escribirían con prefijo core
.
8.3. Lenguaje de expresiones
Para poder conectar las etiquetas de un Facelet con los datos de nuestra aplicación necesitaremos introducir en ellas expresiones que hagan referencia a los managed beans que hayamos definido. Estas expresiones se definen mediante el llamado lenguaje de expresiones (EL).
8.3.1. Introducción al lenguaje de expresiones
A partir de la versión 2.0 de JSP se introdujo en las páginas un lenguaje de expresiones que permite hacer referencia a objetos de la aplicación sin necesidad de introducir código Java. En realidad, dicho lenguaje se implantó con las primeras versiones de JSTL, una librería de etiquetas JSP que se considera estándar, y que permitía utilizar este lenguaje de expresiones en los atributos de dichas etiquetas, constituyendo una característica muy importante de JSTL.
Cualquier elemento que pertenezca al lenguaje de expresiones irá englobado dentro de la marca ${…}
. En ella podremos colocar nombres de managed beans, parámetros de petición HTTP, elementos de una sesión… etc.
Por ejemplo, si previamente hemos creado un managed bean miBean
, podríamos acceder a él desde la página (JSP o Facelet) con algo como:
<h3>El valor del bean es ${miBean}</h3>
Si lo que queremos es mostrar el parámetro password
que hemos tomado de un formulario, para sacarlo por pantalla o guardarlo en alguna base de datos, podríamos acceder a él con algo como:
Accediendo al parámetro ${param.password}
También se pueden utilizar, como veremos, expresiones más complejas, que se evalúan desde el contenedor de Facelets o JSP. Por ejemplo, si tenemos un bean edad
para una persona y queremos comprobar si dicha persona es mayor de edad, podríamos poner:
${edad > 18}
Y luego utilizar el resultado de esta expresión en otras zonas (por ejemplo, etiquetas condicionales de JSTL) para realizar la acción correspondiente.
Se describe a continuación, y a grandes rasgos, el lenguaje de expresiones incluido en JSTL 1.0, y en general a partir de JSP 2.0. El lenguaje está inspirado en los lenguajes ECMAScript y XPath, y está basado en espacios de nombres (atributos PageContext), propiedades de elementos, operadores relacionales, lógicos y aritméticos, y un conjunto de objetos implícitos.
8.3.2. Atributos y expresiones
Como hemos comentado anteriormente, podremos invocar a este lenguaje desde cualquier lugar de nuestra página (en JSP 2.0 o Facelets), o dentro de un atributo de una etiqueta, mediante el elemento ${…}
:
${expresion}
Esta expresión podrá estar:
-
Por sí sola dentro de un atributo de una etiqueta (por ejemplo de JSTL):
<c:set var="miVariable" value="${expresion}"/>
En este caso, se evalúa la expresión y el resultado se convierte al tipo de dato del atributo, siguiendo las reglas de conversión internas del lenguaje.
-
Combinada con texto dentro de un atributo de una etiqueta (por ejemplo de JSTL):
<c:set var="miVariable" value="texto${e1} y ${e2}texto"/>
Aquí, las expresiones se evalúan de izquierda a derecha, y se intercalan entre el texto, convirtiéndolas a String (siguiendo reglas de conversión internas). Luego, la cadena resultante se convierte al tipo del atributo en el que esté (si está dentro de algún atributo).
-
Fuera de atributos, dentro del contenido HTML de la página JSP:
<h3>Hola, esto es una página</h3> <p>Y aquí ponemos una expresión ${expresion}, para mostrar su valor</p>
Para cadenas que contengan la secuencia '${' sin que sea propiamente una expresión, se encapsula esa secuencia así: ${'${'}
. Por ejemplo:
Cadena con ${'${'}expr}
Mostraría: "Cadena con ${expr}"
8.3.3. Operadores
-
Operadores
[ ]
y.
: se unifican los operadores[ ]
y.
de forma que son equivalentes:
${expr.campo}
${expr["campo"]}
-
Operadores aritméticos:
-
+
,-
,*
,/
: suma, resta, multiplicación y división -
div
: división entera -
%
,mod
: resto (se mantienen los dos por compatibilidad con XPath y ECMAScript) -
-
: cambio de signo -
Operadores relacionales:
-
>
,gt
: mayor que -
<
,lt
: menor que -
>=
,ge
: mayor o igual que -
⇐
,le
: menor o igual que -
==
,eq
: igual que -
!=
,ne
: distinto que -
Operadores lógicos:
-
&&
,and
: Y lógica -
||
,or
: O lógica -
!
,not
: NO lógica -
Operador
empty
: utilizado delante de un elemento, para indicar si el elemento es nulo o vacío (devolveríatrue
) o no (devolveríafalse
). Por ejemplo:
${empty A}
PRECEDENCIA
-
[ ]
,.
-
( )
-
-
(cambio de signo),not
,!
,empty
-
*
,/
,div
,%
,mod
-
+
,-
-
<
,>
,⇐
,>=
,lt
,gt
,le
,ge
-
==
,!=
,eq
,ne
-
&&
,and
-
||
,or
EJEMPLOS
// Daría true si el parametro nombre no se ha enviado
${empty param.nombre}
// Devolvería el resultado de la suma de ambas variables
${num1 + num2}
// Devolvería true si valor1 es mayor o igual que valor2
${valor1 >= valor2}
// Daría true si v1 fuese distinto a v2, y v3 menor que v4
${v1 ne v2 and v3 < v4}
8.3.4. Nombres de variables
El lenguaje de expresiones evalúa un identificador o nombre de elemento mirando su valor como un atributo, según el comportamiento del método PageContext.findAttribute(String)
. Por ejemplo, si ponemos:
${valor}
Se buscará el atributo valor en los ámbitos de página (page
), petición (request
), sesión (session
) y aplicación (application
), y si lo encuentra devuelve su valor. Si no, se devuelve null
.
Objetos implícitos
Cuando como nombre de atributo se utiliza alguno de los que el lenguaje de expresiones considera como implícitos, se devolverá el objeto asociado. Dichos objetos implícitos son:
-
pageContext
: el objetoPageContext
actual -
pageScope
,requestScope
,sessionScope
,applicationScope
: para obtener valores de atributos de página / petición / sesión / aplicación, respectivamente. -
param
: para obtener el valor de un parámetro de petición. Se obtiene un tipoString
(utilizando el métodoServletRequest.getParameter(String)
) -
paramValues
: para obtener los valores de un parámetro de petición. Se obtiene un tipoString[]
(utilizando el métodoServletRequest.getParameterValues(String)
). -
header
: para obtener el valor de un parámetro de cabecera. Se obtiene un tipoString
(utilizando el métodoServletRequest.getHeader(String)
) -
headerValues
: para obtener los valores de un parámetro de cabecera. Se obtiene un tipoString[]
(utilizando el métodoServletRequest.getHeaderValues(String)
). -
cookie
: para obtener el valor de una cookie. Se obtiene un objetoCookie
. Las cookies se buscan conHttpServletRequest.getCookies()
-
initParam
: para obtener el valor de un parámetro de inicialización. Se obtiene un tipoString
(utilizando el métodoServletContext.getInitParameter(String)
)
EJEMPLOS
${sessionScope.profile}
Se obtiene el atributo profile
de la sesión
${param.id}
Se obtiene el valor del parámetro id
de la petición, o null
si no se encuentra.
Palabras reservadas
Se tienen algunos identificadores que no podemos utilizar como nombres de atributos, como son and
, eq
, gt
, true
, instanceof
, or
, ne
, le
, false
, empty
, not
, lt
, ge
, null
, div
y mod
.
8.3.5. Lenguaje de expresiones y CDI
Podemos hacer que los beans CDI sean accesibles desde el lenguaje de expresiones. Por defecto no serán accesibles, para poder acceder a ellos deberemos darles un nombre. Esto lo haremos anotando el bean con la etiqueta @Named
:
@Named("hola")
public class HolaMundo {
public String getSaludo() {
return "Hola mundo!";
}
}
Podremos utilizar este bean desde EL de la siguiente forma:
${hola.saludo}
8.4. Librerías de etiquetas
Las librerías de etiquetas (tag libs) son conjuntos de etiquetas HTML personalizadas que permiten encapsular determinadas acciones, mediante un código Java subyacente. Es decir, se define lo que va a ejecutar la etiqueta mediante código Java, y luego se le da un nombre a la etiqueta para llamarla desde los Facelets o páginas JSP, estableciendo la relación entre el nombre de la etiqueta y el código Java que la implementa. Por ejemplo, una página JSP que hace uso de librerías de tags podría tener este aspecto:
<%@ taglib uri="ejemplo" prefix="ej" %>
<html>
<body>
<h1>Ejemplo de librerias de tags</h1>
<ej:mitag>Hola a todos</ej:mitag>
<br>
<ej:otrotag/>
</body>
</html>
donde se utiliza una librería llamada ejemplo
, que se simplifica con el prefijo ej
, de forma que todos los tags de dicha librería se referencian con dicho prefijo y dos puntos, teniendo la forma ej:tag
. Se utilizan así los tags mitag
y otrotag
.
Podríamos incluir dicha librería en un Facelet de la siguiente forma:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ej="ejemplo">
<h:body>
<h1>Ejemplo de librerias de tags</h1>
<ej:mitag>Hola a todos</ej:mitag>
<br/>
<ej:otrotag/>
</h:body>
</html>
JSTL (JavaServer Pages Standard Tag Library) es una librería de tags estándar que encapsula, en forma de tags, muchas funcionalidades comunes en aplicaciones JSP, de forma que, en lugar que tener que recurrir a varias librerías de tags de distintos distribuidores, sólo necesitaremos tener presente esta librería que, además, por el hecho de ser estándar, funciona de la misma forma en cualquier parte, y los contenedores pueden reconocerla y optimizar sus implementaciones.
JSTL permite realizar tareas como iteraciones, estructuras condicionales, tags de manipulación de documentos XML, tags SQL, etc. También introduce un lenguaje de expresiones que simplifica el desarrollo de las páginas, y proporciona un API para simplificar la configuración de los tags JSTL y el desarrollo de tags personalizados que sean conformes a las convenciones de JSTL.
8.4.1. Librería de etiquetas JSTL
JSTL contiene una gran variedad de tags que permiten hacer distintos tipos de tareas, subdivididas en áreas. Así, JSTL proporciona varias sublibrerías, para describir cada una de las áreas que abarca, y dar así a cada área su propio espacio de nombres.
En la siguientes tablas se muestran las áreas cubiertas por JSTL (cada una con una librería):
AREA | URI | PREFIJO |
---|---|---|
Core |
c |
|
XML |
x |
|
Internacionalización (I18N) |
fmt |
|
SQL |
sql |
|
Functions |
fn |
Las URIs mostradas en esta tabla pueden ser utilizadas en páginas JSP. En Facelets/JSF sólo se han incorporado las librerías Core y Functions, siendo sus URIs las siguientes:
AREA | URI | PREFIJO |
---|---|---|
Core |
c |
|
Functions |
fn |
Cada una de estar librerías se encarga de las siguientes funcionalidades:
-
Core se utiliza para funciones de propósito general (manejo de expresiones, sentencias de control de flujo, etc).
-
XML se emplea para procesamiento de ficheros XML.
-
La librería de internationalización se usa para dar soporte a páginas multilenguaje, y a multiformatos de números, monedas, etc, en función de la región en que se tenga la aplicación.
-
SQL sirve para acceder y manipular bases de datos relacionales.
-
Functions contiene una serie de funciones de propósito general, como por ejemplo funciones para la manipulación de cadenas.
Las URIs y prefijos que se indican en la tabla pueden emplearse (aunque no es obligatorio) para utilizar las librerías en nuestros Facelets:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jstl/ea/core"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions">
<h:body>
...
</h:body>
</html>
La librería Core
Los tags core
incluyen tags de propósito general. En esta librería se tienen etiquetas para:
-
Funciones de propósito general: evaluar expresiones, establecer valores de parámetros, etc.
-
Funciones de control de flujo: condiciones para ejecutar unos bloques de código u otro, iteradores, etc.
-
Funciones de acceso a URLs: para importar URLS en la página actual, etc.
Los tags de esta librería se presentan con el prefijo "c".
Tags de propósito general
out
El tag out evalúa el resultado de una expresión y lo pone en el objeto JspWriter
actual. Es equivalente a la sintaxis <%= … %>
de JSP, y también a poner directamente una expresión ${…}
en su lugar, aunque admite algunos atributos adicionales.
SINTAXIS:
Dar el valor por defecto mediante un atributo default
:
<c:out value="valor"
[escapeXML="true|false"]
[default="valor"]/>
Dar el valor por defecto mediante el cuerpo del tag:
<c:out value="valor"
[escapeXML="true|false"]>
Valor por defecto
</c:out>
ATRIBUTOS:
-
value
: expresión que se tiene que evaluar. -
escapeXML
: atrue
(valor por defecto) indica que los caracteres <, >, &, ', " que haya en la cadena resultado se deben convertir a sus códigos correspondientes (<, >, &, ', ", respectivamente). -
default
: valor por defecto si el resultado esnull
. Se puede indicar por el atributo o por el cuerpo del tag.
EJEMPLO:
<c:out value="${datos.ciudad}"
default="desconocida"/>
Sacaría el valor del campo ciudad
del objeto datos
, o mostraría “desconocida” si dicho valor es nulo.
set
El tag set establece el valor de un atributo en cualquier ámbito (page
, request
, session
, application
). Si el atributo no existe, se crea.
SINTAXIS:
Dar valor a una variable utilizando el atributo value
:
<c:set value="valor" var="variable"
[scope="page|request|session|application"]/>
Dar valor a una variable utilizando el cuerpo del tag:
<c:set var="variable"
[scope="page|request|session|application"]>
Valor
</c:set>
Dar valor a una propiedad de un objeto utilizando el atributo value
:
<c:set value="valor" target="objeto"
property="propiedad"/>
Dar valor a una propiedad de un objeto utilizando el cuerpo del tag:
<c:set target="objeto" property="propiedad">
Valor
</c:set>
ATRIBUTOS:
-
value
: valor que se asigna. Podemos dar el valor con este atributo o con el cuerpo del tag. -
var
: variable a la que se asigna el valor. -
scope
: ámbito de la variable a la que se asigna el valor. -
target
: objeto al que se le modifica una propiedad. Debe ser un objeto JavaBeans con una propiedadpropiedad
que pueda establecerse, o un objetojava.util.Map
. -
property
: propiedad a la que se le asigna valor en el objetotarget
.
EJEMPLO:
<c:set var="foo" value="2"/>
...
<c:out value="${foo}"/>
Asignaría a la variable foo
el valor "2", y luego mostraría el valor por pantalla.
Otras Etiquetas
Existen otras etiquetas, como remove
o catch
, que no se comentan aquí.
Tags de control de flujo
if
El tag if permite ejecutar su código si se cumple la condición que contiene su atributo test
.
SINTAXIS:
Sin cuerpo:
<c:if test="condicion" var="variable"
[scope="page|request|session|application"]/>
Con cuerpo:
<c:if test="condicion" [var="variable"]
[scope="page|request|session|application"]>
Cuerpo
</c:if>
ATRIBUTOS:
-
test
: condicion que debe cumplirse para ejecutar elif
. -
var
: variable donde se guarda el resultado de evaluar la expresión. El tipo de esta variable debe serBoolean
. -
scope
: ámbito de la variable a la que se asigna el valor de la condición.
EJEMPLO:
<c:if test="${visitas > 1000}">
<h1>¡Mas de 1000 visitas!</h1>
</c:if>
Sacaría el mensaje “¡Mas de 1000 visitas!” si el contador visitas
fuese mayor que 1000.
choose
El tag choose permite definir varios bloques de código y ejecutar uno de ellos en función de una condición. Dentro del choose
puede haber espacios en blanco, una o varias etiquetas when y cero o una etiquetas otherwise.
El funcionamiento es el siguiente: se ejecutará el código de la primera etiqueta when que cumpla la condición de su atributo test. Si ninguna etiqueta when
cumple su condición, se ejecutará el código de la etiqueta otherwise (esta etiqueta, si aparece, debe ser la última hija de choose
).
SINTAXIS:
<c:choose>
<c:when test="condicion1">
codigo1
</c:when>
<c:when test="condicion2">
codigo2
</c:when>
...
<c:when test="condicionN">
codigoN
</c:when>
<c:otherwise>
codigo
</c:otherwhise>
</c:choose>
EJEMPLO:
<c:choose>
<c:when test="${a < 0}">
<h1>a menor que 0</h1>
</c:when>
<c:when test="${a > 10}">
<h1>a mayor que 10</h1>
</c:when>
<c:otherwise>
<h1>a entre 1 y 10</h1>
</c:otherwhise>
</c:choose>
Sacaría el mensaje “a es menor que 0” si la variable a es menor que 0, el mensaje “a es mayor que 10” si es mayor que 10, y el mensaje “a esta entre 1 y 10” si no se cumple ninguna de las dos anteriores.
forEach
El tag forEach permite repetir su código recorriendo un conjunto de objetos, o durante un número determinado de iteraciones.
SINTAXIS:
Para iterar sobre un conjunto de objetos:
<c:forEach [var="variable"] items="conjunto"
[varStatus="variableEstado"] [begin="comienzo"]
[end="final"] [step="incremento"]>
codigo
</c:forEach>
Para iterar un determinado número de veces:
<c:forEach [var="variable"]
[varStatus="variableEstado"] begin="comienzo"
end="final" [step="incremento"]>
codigo
</c:forEach>
ATRIBUTOS:
-
var
: variable donde guardar el elemento actual que se está explorando en la iteración. El tipo de este objeto depende del tipo de conjunto que se esté recorriendo. -
items
: conjunto de elementos que recorre la iteración. Pueden recorrerse varios tipos:-
Array
: tanto de tipos primitivos como de tipos complejos. Para los tipos primitivos, cada dato se convierte en su correspondientewrapper
(Integer
paraint
,Float
parafloat
, etc) -
java.util.Collection
: mediante el métodoiterator()
se obtiene el conjunto, que se procesa en el orden que devuelve dicho método. -
java.util.Iterator
-
java.util.Enumeration
-
java.util.Map
:el objeto del atributovar
es entonces de tipoMap.Entry
, y se obtiene unSet
con los mapeos. Llamando al métodoiterator()
del mismo se obtiene el conjunto a recorrer. -
String
: la cadena representa un conjunto de valores separados por comas, que se van recorriendo en el orden en que están.
-
-
varStatus
: variable donde guardar el estado actual de la iteración. Es del tipojavax.servlet.jsp.jstl.core.LoopTagStatus
. -
begin
: indica el valor a partir del cual comenzar la iteración. Si se está recorriendo un conjunto de objetos, indica el índice del primer objeto a explorar (el primero es el 0), y si no, indica el valor inicial del contador. Si se indica este atributo, debe ser mayor o igual que 0. -
end
: indica el valor donde terminar la iteración. Si se está recorriendo un conjunto de objetos, indica el índice del último objeto a explorar (inclusive), y si no, indica el valor final del contador. Si se indica este atributo, debe ser mayor o igual quebegin
. -
step
: indica cuántas unidades incrementar el contador cada iteración, para ir debegin
aend
. Por defecto es 1 unidad. Si se indica este atributo, debe ser mayor o igual que 1.
EJEMPLO:
<c:forEach var="item"
items="${cart.items}">
<tr>
<td>
<c:out value="${item.valor}"/>
</td>
</tr>
</c:forEach>
Muestra el valor de todos los items
.
forTokens
El tag forTokens es similar al tag foreach, pero permite recorrer una serie de tokens
(cadenas de caracteres), separadas por el/los delimitador(es) que se indique(n).
SINTAXIS:
La sintaxis es la misma que foreach
, salvo que se tiene un atributo delims
, obligatorio.
ATRIBUTOS:
-
var
: igual que paraforeach
-
items
: cadena que contiene los tokens a recorrer -
delims
:conjunto de delimitadores que se utilizan para separar los tokens de la cadena de entrada (colocados igual que los utiliza unStringTokenizer
). -
varStatus
: igual que paraforeach
-
begin
: indica el índice del token a partir del cual comenzar la iteración. -
end
: indica el índice del token donde terminar la iteración. -
step
: igual que paraforeach
.
EJEMPLO:
<c:forTokens var="item"
items="un#token otro#otromas" delims="# ">
<tr>
<td>
<c:out value="${item}"/>
</td>
</tr>
</c:forEach>
Definimos dos separadores: el '#'
y el espacio ' '
. Así habrá 4 iteraciones, recorriendo los tokens "un"
, "token"
, "otro"
y "otromas"
.
Tags de manejo de URLs
import
El tag import permite importar el contenido de una URL.
SINTAXIS:
Para copiar el contenido de la URL en una cadena:
<c:import url="url" [context="contexto"]
[var="variable"]
[scope="page|request|session|application"]
[charEncoding="codificacion"]>
cuerpo para tags "param" opcionales
</c:import>
Para copiar el contenido de la URL en un Reader
:
<c:import url="url" [context="contexto"]
varReader="variableReader"
[charEncoding="codificacion"]>
codigo para leer del Reader
</c:import>
ATRIBUTOS:
-
url
: URL de la que importar datos -
context
: contexto para URLs que pertenecen a contextos distintos al actual. -
var
: variable (String
) donde guardar el contenido de la URL -
varReader
: variable (Reader
) donde guardar el contenido de la URL -
scope
: ámbito para la variablevar
-
charEncoding
: codificación de caracteres de la URL
EJEMPLO:
<c:import url="http://www.ua.es"
var="universidad">
<c:out value="${universidad}"/>
</c:import>
Obtiene y muestra el contenido de la URL indicada.
param
El tag param
se utiliza dentro del tag import
y de otros tags (redirect
, url
) para indicar parámetros de la URL solicitada. Dentro del tag import
sólo se utiliza si la URL se guarda en una cadena. Para los Readers
no se emplean parámetros.
SINTAXIS:
Sin cuerpo:
<c:param name="nombre" value="valor"/>
Con cuerpo:
<c:param name="nombre">
Valor
</c:param>
ATRIBUTOS:
-
name
: nombre del parámetro -
value
: valor del parámetro. Puede indicarse bien mediante este atributo, bien en el cuerpo del tag.
EJEMPLO:
<c:import url="http://localhost/mipagina.jsp"
var="universidad">
<c:param name="id" value="12"/>
</c:import>
Obtiene la página mipagina.jsp?id=12
(le pasa como parámetro id
el valor 12).
Otras Etiquetas
Existen otras etiquetas, como url
o redirect
, que no se comentan aquí.
Ejemplo
Vemos cómo quedaría el ejemplo visto en la sesión anterior para la librería request
adaptado a la librería core
. Partiendo del mismo formulario inicial:
<html>
<body>
<form action="request.jsp">
Nombre:
<input type="text" name="nombre">
<br>
Descripcion:
<input type="text" name="descripcion">
<br>
<input type="submit" value="Enviar">
</form>
</body>
</html>
Para obtener los parámetros podríamos tener una página como esta:
<%@ taglib uri="http://java.sun.com/jstl/ea/core" prefix="c" %>
<html>
<body>
Nombre: <c:out value="${param.nombre}"/>
<br>
<c:if test="${not empty param.descripcion}">
Descripcion: <c:out value="${param.descripcion}"/>
</c:if>
</body>
</html>
Hemos utilizado en este caso, como ejemplo, los tags out
e if
(para comprobar si hay parámetro descripcion
). En este último caso, utilizamos el operador empty
en el lenguaje de expresiones, para ver si hay o no valor.
La librería de funciones
JSTL dispone también de un conjunto de funciones que pueden emplearse desde dentro del lenguaje de expresiones, y permiten sobre todo manipular cadenas, para sustituir caracteres, concatenar, etc.
Para utilizar estas funciones, cargaríamos la directiva taglib
correspondiente:
<%@ taglib uri="http://java.sun.com/jstl/ea/functions" prefix="fn" %>
Y luego utilizaríamos las funciones que haya disponibles, dentro de una expresión del lenguaje:
La cadena tiene <c:out value="${fn:length(miCadena)}"/> caracteres
8.4.2. Librerías de JSF/Facelets
Hemos visto hasta el momento librerías de JSTL que podemos utilizar dentro de los Facelets, pero que también encontraremos dentro de otros frameworks. Vamos a ver ahora algunas librerías propias de Facelets/JSF, como la librería HTML de JSF y la librería UI de Facelets que nos permitirá crear plantillas para las páginas.
Librería HTML de JSF
Una de las principales librerías de etiquetas utilizada en Facelets es la librería HTML de JSF. Esta librería contiene una serie de componentes de la interfaz que se renderizarán en la página como HTML. Gran parte de los componentes de esta librería son campos de formularios, cuyo valor puede vincularse con managed beans y podemos establecer la forma mediante etiquetas de la librería de funciones de JSF. Por ejemplo podríamos tener un campo de texto como el siguiente:
<h:inputText id="precio"
size="4"
value="#{articulo.precio}"
title="Cantidad">
<f:validateLongRange minimum="0"/>
</h:inputText>
En el ejemplo anterior se crea un campo de texto que se renderizará como una etiqueta <input>
en el HTML resultante, y quedará vinculado en el servidor con el precio del managed bean articulo
. Además, se especifica que el campo debe ser validado de forma que nunca tenga un valor inferior a 0
.
Encontramos otras etiquetas como las siguientes dentro de esta librería:
Etiqueta | Función |
---|---|
|
Representa un enlace a otra página, se renderiza como |
|
Tabla que se puede actualizar de forma dinámica, se renderiza como |
|
Representa una columna en una tabla |
|
Representa una fila en una tabla, se renderiza como |
|
Muestra una imagen, se renderiza como |
|
Muestra texto plano |
|
Permite especificar una hoja de estilo |
|
Equivalente a |
|
Equivalente a |
En todas estas etiquetas encontramos una serie de atributos comunes:
Atributo | Función |
---|---|
|
Identifica al componente de forma única. |
|
Podemos especificar una condición mediante EL que indica si el componente se debe mostrar o no. |
|
Especifica el estilo CSS. |
|
Especifica una clase de estilo. |
Recursos
Hablamos de recursos para referirnos a cualquier artefacto que una página web necesita para mostrarse correctamente, como son las imágenes, ficheros JavaScript, hojas de estilo, etc. En los Facelets podremos hacer referencia a estos recursos simplemente indicando el nombre del recurso, siempre que éstos se encuentren en determinadas ubicaciones estándar. Estas ubicaciones son:
-
Directorio
resources
en la raíz del contexto. -
Dentro del classpath, en
META-INF/resources
.
Si el recurso se encuentra en una de las localizaciones anteriores podemos hacer referencia a él únicamente mediante su nombre en los atributos de las etiquetas de JSF/Facelets, como por ejemplo:
<h:outputStylesheet library="css" name="estilo.css"/>
En este caso podríamos tener la hoja de estilo en /resources/css/estilo.css
.
Podemos también hacer referencia a la ubicación mediante lenguaje de expresiones:
<h:graphicImage value="#{resource['imagenes:logo.gif']}"/>
En el caso anterior buscará la imagen en /resources/imagenes/logo.gif
.
Plantillas
La tecnología de Facelets nos permite crear plantillas para las páginas. Estas plantillas definen una determinada disposición de los elementos en el documento, y podrán ser aplicadas a diferentes páginas para así tener una estructura homogénea en todo el sitio web. En estas plantillas por ejemplo podríamos definir un bloque de cabecera, menú lateral, cuerpo de la página, pie de página, etc.
Para la creación de plantillas utilizaremos la librería de Interfaz de Usuario (UI) de Facelets:
<!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://xmlns.jcp.org/jsf/facelets" (1)
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8" />
<h:outputStylesheet library="css" name="estilo.css"/>
<title>Plantilla con Facelets</title>
</h:head>
<h:body>
<div id="top" class="top">
<ui:insert name="cabecera">Cabecera</ui:insert> (2)
</div>
<div>
<div id="left">
<ui:insert name="menu">Menú lateral</ui:insert>
</div>
<div id="content" class="content">
<ui:insert name="cuerpo">Cuerpo de la página</ui:insert>
</div>
</div>
</h:body>
</html>
1 | Declaramos la librería UI de Facelets |
2 | Utilizamos <ui:insert> para crear un lugar donde insertar contenido dentro de la plantilla general. |
En el ejemplo anterior hemos creado una plantilla de página web donde se definen tres lugares donde vamos a poner insertar contenido: cabecera
, menu
y cuerpo
. Vamos a crear a continuación una página que se ajuste a dicha plantilla e inserte contenido en cada una de las secciones.
Consideremos que el fichero anterior con la plantilla ha sido guardado con el nombre plantilla.xhtml
. Una página que utilice dicha plantilla podría definirse de la siguiente forma:
<!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://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:body>
<ui:composition template="./plantilla.xhtml"> (1)
<ui:define name="cabecera"> (2)
Título de la página
</ui:define>
<ui:define name="menu">
<h:outputLabel value="Menú"/>
</ui:define>
<ui:define name="cuerpo">
<h:graphicImage value="#{resource['images:logo.gif']}"/>
<h:outputText value="2014 (c) DCCIA"/>
</ui:define>
</ui:composition>
</h:body>
</html>
1 | Con la etiqueta <ui:composition> indicamos la plantilla que vamos a utilizar. |
2 | Con la etiqueta <ui:define> indicamos el contenido que vamos a insertar en cada una de las secciones de la plantilla utilizada. |
Vemos en el ejemplo anterior que podremos poner una etiqueta <ui:define>
por cada elemento definido mediante <ui:insert>
en la plantilla que estamos utilizando.
8.5. Ejercicios
8.5.1. Página de chat con Facelets (1 punto)
Vamos a crear una implementación alternativa del listado de mensajes del chat mediante un Facelet que utilice la librería JSTL y el lenguaje de expresiones. Los Facelets son más apropiados que los Servlets para crear la vista de la aplicación, por lo que será conveniente pasar la presentación que actualmente está realizando ListaMensajesServlet
a un Facelet.
Seguiremos los siguientes pasos:
-
Añade la configuración de JSF al proyecto desde IntelliJ. Se deberá crear el fichero
faces-config.xml
enWEB-INF
y mapear el Faces Servlet a las direcciones de tipo*.xhtml
. -
Crea desde IntelliJ un nuevo Facelet llamado
listaMensajes.xhtml
en el directoriowebapp/chat
. -
Importa en el Facelet la librería JSTL Core.
-
Crearemos un recuadro para el chat siguiendo el mismo estilo de las páginas utilizadas en sesiones anteriores. Esta vez podemos importar la hoja de estilo
estilo.css
como un recurso.Deberemos copiar el fichero estilo.css
a un directorio donde pueda ser importado como recurso (webapp/resources
). -
En la cabecera del cuadro del chat indicaremos el nombre del usuario que hay actualmente conectado. Podemos poner un mensaje como "Conectado al chat como <nombre>".
El nombre del atributo donde se guarda el nick es org.expertojava.cweb.chat.nick
, lo cual puede causar problemas al utilizarlo dentro del lenguaje de expresiones. Para evitar estos problemas podríamos utilizar una sintaxis como${sessionScope["nombre_atributo"]}
. -
Utilizaremos un managed bean para mostrar los mensajes en la página. Deberemos:
-
Si la cola está vacía, mostraremos el mensaje "Todavía no se ha enviado ningún mensaje al chat".
-
Si la cola tiene mensajes, iteraremos por la cola para mostrar todos los mensajes junto al nombre del usuario que los envió.
-
No podemos utilizar directamente el objeto ColaMensajes dentro del lenguaje de expresiones al tratarse de un objeto de tipo LinkedList . Podemos crearnos un nuevo managed bean que nos dé acceso a dicha lista mediante uno de sus atributos. Por ejemplo, podríamos crear un objeto Chat dentro del ámbito de la aplicación con un atributo cola en el que inyectaremos el objeto ColaMensajes . De esta forma podríamos acceder a ella desde lenguaje de expresiones con ${chat.cola} .
|
Todo lo anterior debe realizarse utilizando únicamente JSTL y lenguaje de expresiones.