Sie sind auf Seite 1von 54

Java Server Faces (JSF)

Autor: Antonio J. Martín


ÍNDICE

1. INTRODUCCIÓN................................................................................................... 5
1.1. CARACTERÍSTICAS DE JSF ................................................................................... 5

2. COMPONENTES DE UNA APLICACIÓN JSF .................................................... 5


2.1. ARCHIVO DE CONFIGURACIÓN FACES-CONFIG.XML ................................................. 6

2.2. SERVLET FACESSERVLET..................................................................................... 6

2.3. BEANS GESTIONADOS .......................................................................................... 7

2.4. CONTEXTO DE APLICACIÓN. LA CLASE FACESCONTEXT ......................................... 8

2.5. ACCIONES JSP.................................................................................................... 9

3. CREACIÓN DE UNA PRIMERA APLICACIÓN JSF............................................ 9


3.1. CREACIÓN DE LA ESTRUCTURA DE LA APLICACIÓN................................................ 10

3.2. IMPLEMENTACIÓN DEL MODELO ........................................................................... 11

3.3. CREACIÓN Y REGISTRO DE BEANS GESTIONADOS ................................................. 11

3.4. IMPLEMENTACIÓN DE CONTROLADORES DE ACCIÓN.............................................. 11

3.5. DEFINICIÓN DE REGLAS DE NAVEGACIÓN ............................................................. 12

3.6. CREACIÓN DE LAS VISTAS ................................................................................... 13

EJERCICIO 1.................................................................................................. 16

EJERCICIO 2.................................................................................................. 20

4. EVENTOS DE ACCIÓN (ACTIONEVENT)......................................................... 24

5. CICLO DE VIDA DEL PROCESAMIENTO DE UNA PETICIÓN JSF................ 26


5.1. RESTORE VIEW.................................................................................................. 27

5.2. APPLY REQUEST VALUES ................................................................................... 28

5.3. PROCESS VALIDATION ........................................................................................ 28

5.4. UPDATE MODEL VALUES .................................................................................... 28

5.5. INVOKE APPLICATION ......................................................................................... 28

5.6. RENDER RESPONSE........................................................................................... 29

6. COMPONENTES GRÁFICOS JSF..................................................................... 29


6.1. RENDERIZACIÓN ................................................................................................ 30

6.2. TAGS DE COMPONENTES JSF ............................................................................. 30


6.2.1. Formulario ................................................................................................. 32

6.2.2. Controles: atributos comunes. .................................................................. 32

6.2.3. Campos de texto ....................................................................................... 32

6.2.4. Controles de comando .............................................................................. 33

6.2.5. Generación de texto .................................................................................. 33

6.2.6. Casillas de verificación.............................................................................. 33

6.2.7. Listas de selección única .......................................................................... 33

6.2.7.1. Componentes de una lista ................................................................. 34

6.2.8. Listas de selección múltiple ...................................................................... 35

6.3. EL EVENTO VALUECHANGEEVENT ...................................................................... 36

EJERCICIO 3.................................................................................................. 36

7. CONVERSORES Y VALIDADORES.................................................................. 41
7.1. VALIDADORES .................................................................................................... 42

7.1.1. Validación automática ............................................................................... 42

7.1.2. Validadores implícitos JSF........................................................................ 45

7.1.3. Validadores personalizados ...................................................................... 46

7.2. CONVERSORES .................................................................................................. 47

7.2.1. Conversores implícitos JSF ...................................................................... 48


1. INTRODUCCIÓN
JavaServer Faces (JSF) es un framework, incluido dentro de la especificación Java EE,
que tiene como misión facilitar la construcción y mantenimiento de aplicaciones Web en Java,
siguiendo la arquitectura Modelo Vista Controlador.

En la definición anterior hemos indicado una característica que hace especial a JSF y la
diferencia de otros frameworks existentes, también orientados a la creación de aplicaciones
MVC, como Struts; se trata del hecho de que JSF es parte de la especificación Java EE. Esto
implica que la mayoría de las herramientas creadas por terceros fabricantes para trabajar con
Java EE soportan esta tecnología, convirtiendo así a JSF en el framework más “estandarizado”
de todos los existentes y favoreciendo su rápida extensión.

1.1. CARACTERÍSTICAS DE JSF

Además de lo comentado anteriormente, otras características que nos ofrece este


framework son:

Componentes de la interfaz de usuario. Habitualmente se suele decir que


JSF es un framework de interfaz de usuario, lo cual es debido al amplio
conjunto de componentes incluidos en el API JSF orientados a la creación de
elementos gráficos. Con ellos podemos construir potentes interfaces gráficas
de una manera sencilla e independiente de la tecnología utilizada para el
desarrollo de la vista, es decir, no sólamente podemos emplear estos
componentes con páginas JSP, sino también con otras tecnologías como por
ejemplo velocity.

Modelo de navegación declarativo. Como en cualquier aplicación que siga el


patrón MVC, las peticiones son dirigidas al Controlador que se encarga de
analizarlas, despacharlas e invocar a la vista adecuada para la generación de
la respuesta. En el caso de JSF la información referente a las posibles vistas
que deben ser generadas para cada página origen de la petición se encuentra
registrada en un archivo de configuración propio de JSF, llamado faces-
config.xml. Esta información, conocida como reglas de navegación, es
consultada por el Controlador tras el procesamiento de una petición cliente.

Ejecución basada en eventos. De manera similar a como funcionan las


aplicaciones de escritorio, la programación de una aplicación JSF está basada
en parte en la captura de eventos sobre la interfaz gráfica. A través de los
atributos de las acciones JSF que representan a los componentes gráficos, es
posible asociar estos eventos con métodos de respuesta implementados en
los beans gestionados u otras clases del Controlador, de modo que cuando se
lance una petición desde la página a la aplicación (lo que se conoce como un
postback) el framework será capaz de detectar los eventos producidos y
ejecutar los métodos de respuesta a los mismos en el orden en que han tenido
lugar.

2. COMPONENTES DE UNA APLICACIÓN JSF


Como sucede con otros frameworks, JSF está orientado a prestar soporte para la
construcción de las capas Controlador y Vista de la aplicación, implementándose el Modelo con
los elementos habituales para la encapsulación de la lógica de negocio: clases estándares y
EJBs.
En lo que respecta a las otras dos capas de la aplicación, Controlador y Vista, la
tecnología JSF aporta los siguientes elementos:

2.1. ARCHIVO DE CONFIGURACIÓN FACES-CONFIG.XML

Se utiliza para definir diversos elementos clave para el funcionamiento de la aplicación


JSF, como las reglas de navegación o los beans gestionados y su ámbito de utilización.

Esta información es utilizada por el controlador FacesServlet para despachar las


peticiones que llegan a la aplicación y activar las vistas que deben generar las respuestas al
cliente en cada caso.

La estructura de un documento faces-config es la que se muestra en el siguiente


listado:

<?xml version='1.0' encoding='UTF-8'?>


<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces
Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
:
</faces-config>

2.2. SERVLET FACESSERVLET.

Incluido dentro del paquete javax.faces.webapp, este servlet constituye el punto de


entrada a la aplicación Web, haciendo las tareas de Front Controler. A el llegan todas las
peticiones procedentes de la capa cliente, encargándose de despachar cada una de ellas en
función de la información almacenada en el archivo de configuración faces-config.xml.

Como sucede con cualquier otro servlet de una aplicación, FacesServlet debe ser
registrado en el archivo de configuración web.xml. Por convención suele utilizarse la expresión
“/faces/*” como patrón de URL asociado al servlet, lo que significa que cualquier URL relativa
que comience por “/faces/” provocará la ejecución del servlet. He aquí el bloque de sentencias
de configuración típico de FacesServlet:

<!-- Faces Servlet -->


<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>

2.3. BEANS GESTIONADOS

Los beans gestionados son uno de los elementos más característicos de una aplicación
JSF. Se trata de simples JavaBeans que, además de ser utilizados para la encapsulación de
los datos procedentes de la capa cliente, incluyen los métodos de respuesta a los eventos
producidos en la capa cliente.

Buscando una comparativa con struts, un bean gestionado es una combinación de un


ActionForm y un Action en una misma clase, con la particularidad añadida de que el bean
gestionado es implementado mediante una simple clase POJO (Plain and Old Java Object), es
decir, una clase que no necesita heredar ni implementar ninguna clase o interfaz especial.
Precisamente se les llama gestionados porque es el propio framework el que se encarga
totalmente de la gestión de su ciclo de vida, es decir, de su instanciación, recuperación,
rellenado de datos, invocación a los métodos de respuesta a eventos, etc. El programador
simplemente tendrá que codificarlo y registrarlo en el archivo de configuración de JSF.

El siguiente ejemplo representa un bean que encapsula los credenciales de usuario e


incluye un método para realizar la validación del mismo:

package javabeans;
public class CredencialesBean {
private String user;
private String password;
public CredencialesBean () {
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String doLogin(){
if(password.equals(“admin”)){
return “valido”;
}
else{
return “novalido”;
}
}
}

El método doLogin() es el llamado controlador de acción o método de aplicación.


Se trata de un método asociado a los controles de comando (componentes gráficos
UICommand que pueden ser representados como un botón de pulsación o un enlace). Cada
vez que uno de estos controles es activado, se lanza una petición a la aplicación
(postback) que hará que se ejecute este método. Más adelante analizaremos el significado
del objeto String devuelto por este tipo de métodos.

En caso de requerir una lógica de negocio más compleja para realizar la validación de
los datos, que incluyera por ejemplo un acceso a los datos, dichas operaciones serían aisladas
en una clase o EJB independiente, incluyendo únicamente el método doLogin() la llamada a los
métodos de negocio.

Para registrar este bean en el archivo faces-config.xml habría que incluir el siguiente
bloque de texto en el interior del elemento faces-config:

<managed-bean>
<managed-bean-name>credencialesBean</managed-bean-name>
<managed-bean-class>
javabeans.CredencialesBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

A continuación se explica el significado de los elementos utilizados para el registro de


un bean gestionado:

managed-bean. Es el elemento principal en el que se incluyen los datos de


registro del bean. Será necesario añadir un bloque <managed-bean> por cada
bean que se quiera sea gestionado por el framework.

managed-bean-name. Es el nombre que permite referirse a la instancia del


bean. Este nombre es utilizado mediante el lenguaje EL desde los componentes
de la interfaz para acceder a las propiedades y métodos del objeto.

managed-bean-class. Nombre cualificado de la clase a la que pertenece el


bean.

managed-bean.scope. Ámbito en el que será mantenida la instancia, siendo sus


posibles valores: request, session y application.

El bean gestionado es parte tanto de la Vista como del Controlador ya que es utilizado
por ambas capas, en el primer caso para almacenar los datos cliente y en el segundo para
despachar la petición.

2.4. CONTEXTO DE APLICACIÓN. LA CLASE FACESCONTEXT

Las aplicaciones JSF deben ser capaces de almacenar información sobre la petición en
curso. Toda esta información es accesible al programador a través de la clase FacesContext
existente en el paquete javax.faces.context.

Más adelante veremos algunas de las aplicaciones más importantes de esta clase.
2.5. ACCIONES JSP

Como se ha indicado con anterioridad, JSF incluye un elevado número de


componentes gráficos para la construcción de potentes interfaces de usuario.

En el caso de que las vistas sean implementadas mediante páginas JSP el acceso a
estos componentes se realizará a través de una serie de librerías de acciones JSP.
Concretamente, la especificación JSP incluye dos tipos de librerías de acciones:

La librería html. Esta librería proporciona además de los controles básicos html
con capacidades mejoradas, una serie de componentes gráficos complejos
orientados a la presentación de datos en la página. Todos los controles incluidos
en esta librería se integran perfectamente con el modelo de JavaBean de Java,
permitiendo vincular de manera automática las propiedades de un objeto con las
de un control de la interfaz.

Para poder hacer uso de esta librería en el interior de una página JSP se debería
incluir la siguiente directiva taglib:

<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>


La siguiente etiqueta representa un ejemplo de uso de un componente gráfico de
tipo caja de texto, en el que a través del elemento value conseguimos vincular el
contenido del control a un la propiedad de un JavaBean:

<h:inputText value="${credencialesBean.user}"/>
La librería core. Además de incluir elementos básicos para la generación de una
vista JSF, esta librería proporciona unos componentes especiales conocidos
como validadores y conversores que permiten realizar validaciones y
conversiones de datos, respectivamente, de la información suministrada por el
usuario a través de la interfaz, todo ello de manera que el programador no tenga
que incluir una sola línea de código para esta tarea.

La directiva taglib necesaria para utilizar las acciones de esta librería sería:

<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>

3. CREACIÓN DE UNA PRIMERA APLICACIÓN JSF


Vamos a realizar una sencilla aplicación que nos permita poner en práctica los
conceptos explicados anteriormente, así como conocer el proceso básico de creación de una
aplicación basada en este framework.

La aplicación consistirá en validar los credenciales introducidos por el usuario a través


de una página de login. Si el usuario es válido se mostrará una página con los dos datos
introducidos y si no se le llevará a una página de error. El esquema con las tres páginas
involucradas se muestra en la figura 1.
login.jsp valido.jsp
Password
correcto

novalido.jsp

Password
incorrecto

Figura. 1.

Vamos a ir viendo los pasos que tenemos que seguir para construir la aplicación.

3.1. CREACIÓN DE LA ESTRUCTURA DE LA APLICACIÓN.

En este primer paso debemos crear la estructura de la aplicación Web y añadir las
librerías necesarias para trabajar con JSF, así como crear el archivo de configuración faces-
config.xml y registrar el servlet FacesServlet en el web.xml.

Si contamos con un entorno de desarrollo como NetBeans todas estas operaciones se


pueden realizar de forma automática. Para ello, en el asistente de creación de aplicación Web
debemos activar en el último paso la casilla correspondiente al framework JavaServer Faces,
tal y como se indica en la figura 2.

Figura. 2.

Con esto no sólo se creará la estructura de la aplicación Web, sino que también se
llevarán a cabo las operaciones descritas anteriormente.
3.2. IMPLEMENTACIÓN DEL MODELO

Como se indicó anteriormente, la implementación de la capa de negocio en una


aplicación JSF es un proceso en el que no interviene ningún elemento de está tecnología.

El desarrollo de estos componentes de negocio puede realizarse de manera


independiente al resto de las capas.

En este ejemplo no hay que desarrollar ninguna clase de negocio, puesto que la única
lógica existente irá incluida en el método controlador de acción que será ejecutado con la
pulsación del botón “Aceptar”.

3.3. CREACIÓN Y REGISTRO DE BEANS GESTIONADOS

El único bean gestionado que utilizaremos en esta aplicación será el CredencialesBean


presentado anteriormente, registrándolo en el archivo faces-config.xml mediante el bloque de
sentencias XML indicado.

El archivo faces-config.xml podemos encontrarlo en la carpeta configuration files de


NetBeans.

3.4. IMPLEMENTACIÓN DE CONTROLADORES DE ACCIÓN

Los métodos controladores de acción, se implementan en los propios beans


gestionados. Estos métodos serán ejecutados por el controlador tras procesarse la petición
generada por control de comando, después de que se hayan rellenado los campos del bean
con los datos recibidos en la petición.

Como resultado de su ejecución, los controladores de acción deben devolver un String


que es utilizado por FacesServlet para determinar la siguiente vista que deberá ser invocada,
información esta que se encuentra definida en las reglas de navegación dentro de faces-config.

En nuestra aplicación de ejemplo, el método doLogin() correspondiente a la pulsación


del botón “Aceptar” es bastante simple:

public String doLogin(){


if(password.equals("admin")){
return "valido";
}
else{
return "novalido";
}
}

Como vemos se devuelven dos posibles valores en función de si el password se


considera o no válido. Dichos valores determinarán a donde será redirigido el usuario.

Aunque en este ejemplo no hemos tenido necesidad de ello, en numerosas ocasiones


puede ocurrir que necesitemos acceder desde el controlador de acción a alguno de los objetos
clásicos del API servlet para interactuar con la aplicación Web.

A diferencia de los métodos execute() de los objetos de Struts, donde se recibía como
parámetros referencias a los objetos HttpServletRequest y HttpServletResponse, los métodos
controladores de acción de los beans gestionados no reciben ningún parámetro. No
obstante, se puede acceder al contexto de aplicación desde estos métodos a través de la clase
javax.faces.context.ExternalContext cuyos métodos getRequest(), getResponse(),
getSession(), etc. nos devuelven referencias a los distintos objetos de aplicación.

Para poder obtener un objeto ExternalContext debemos recurrir a la clase


FacesContext existente en el mismo paquete. El siguiente bloque de instrucciones de ejemplo
sería el código que deberíamos utilizar para obtener un objeto Request desde un método de
acción:

FacesContext context=FacesContext.getCurrentInstance();
ExternalContext excontext=context. getExternalContext();
HttpServletRequest request=
(HttpServletRequest)excontext. getRequest();

3.5. DEFINICIÓN DE REGLAS DE NAVEGACIÓN

Las reglas de navegación determinan el flujo de navegación entre las distintas vistas de
la aplicación. Las reglas de navegación son aplicadas por FacesServlet cuando éste recibe una
petición desde el navegador, con motivo de la generación de un evento de acción en la página
cliente.

En cada regla de navegación se indican, para cada página origen, las posibles páginas
destino a las que será redirigido el usuario en función de los valores devueltos por el método de
acción. Una regla de navegación se define mediante el elemento <navigation-rule>, el cual
incluirá los siguientes sub elementos:

from-view-id. URL relativa de la página origen para la que se define la regla de


navegación.

navigation-case. Define el posible destino al que será reenviada la petición del


usuario. Cada uno de estos posibles destinos requiere su propio <navigation-
case> que deberá incluir a su vez los siguientes subelementos:

- from-outcome. Valor devuelto por el método de acción, que provocará


la navegación a este destino.

- to-view-id. URL relativa de la vista destino.

En el ejemplo que estamos desarrollando únicamente debemos incluir la regla de


navegación asociada al evento del botón “Aceptar” de la página login.jsp, regla que
indicaremos a continuación de la definición de los beans gestionados:

<?xml version='1.0' encoding='UTF-8'?>


<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config
1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

<!-- ======= FULL CONFIGURATION FILE ================== -->

<faces-config>
<managed-bean>
<managed-bean-name>credencialesBean</managed-bean-name>
<managed-bean-class>javabeans.CredencialesBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/login.jsp</from-view-id>
<navigation-case>
<from-outcome>valido</from-outcome>
<to-view-id>/valido.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>novalido</from-outcome>
<to-view-id>/novalido.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>

Algo muy importante que debemos tener en cuenta a la hora de definir reglas de
navegación es que, si el valor devuelto por alguno de los métodos de acción incluidos en la
página origen no coincide con ninguno de los valores indicados en los elementos <from-
outcome>, se producirá la recarga de la página origen.

3.6. CREACIÓN DE LAS VISTAS

Finalmente, procedemos a crear las distintas vistas de la aplicación. Todas las


páginas JSP en las que vayamos a hacer uso de algunas de las librerías de acciones JSF
deberán incluir el elemento <f:view> de la libraría core, dentro del cual se incluirán el resto
de acciones JSF de la página.

En el caso de la página login.jsp, utilizaremos las acciones inputText e inputSecret de


JSF para generar los campos de texto “usuario” y “password”, respectivamente. Estas acciones
disponen de un atributo value que nos permite vincular los controles con las propiedades
de un bean gestionado, mostrando en su interior el valor de la propiedad cuando la página es
cargada y volcando en la propiedad el contenido del campo cuando se produce el submit de la
página.

Por su parte, el botón “Aceptar” será generado mediante la acción commandButton, en


cuyo atributo action habrá que indicar, mediante notación EL, el nombre del método
controlador de acción que habrá que invocar cuando se produzca la pulsación del botón.
Como ya se indicó con anterioridad, la activación de este tipo de controles provoca
automáticamente el submit o postback de la página.

He aquí el código completo de la página login.jsp:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<br/><br/>
<center><h1>Página de validación</h1></center>
<f:view>
<h:form>
<table width="50%" align="center" border="0">
<tr>
<td>Nombre usuario:</td>
<td><h:inputText
value="#{credencialesBean.user}"/></td>
</tr>
<tr>
<td>Contraseña:</td>
<td><h:inputSecret
value="#{credencialesBean.password}"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<h:commandButton value="Aceptar"
action="#{credencialesBean.doLogin}"/>
</td>
</tr>
</table>
</h:form>
</f:view>
</body>
</html>
Pudiera ocurrir que la pulsación de un botón de comando no tuviera que ejecutar
ningún código de servidor concreto, tan solo producir una navegación estática a una
determinada vista de la aplicación. En este caso, basta con indicar como valor del atributo
action la cadena de caracteres asociada a la página destino en la regla de navegación.
En cuanto a la página valido.jsp encargada de mostrar los credenciales del usuario
válido, utiliza un elemento outputText para mostrar el valor de cada dato. Este elemento realiza
la misma función que una expresión JSP:

<%=expresion%>

En su atributo value se deberá indicar el valor a mostrar, que podrá ser una cadena de
texto estática o una expresión EL que devuelva algún dato existente en cualquiera de los
ámbitos de aplicación. En este caso, se utiliza una expresión EL para acceder a las
propiedades del bean credencialesBean, que al tener ámbito de petición (request) es accesible
desde esta página. El código de la página valido.jsp se muestra en el siguiente listado:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<f:view>
<h2>Sus datos:</h2>
Usuario: <h:outputText
value="#{credencialesBean.user}"/><br/>
Password: <h:outputText
value="#{credencialesBean.password}"/><br/>
</f:view>
</body>
</html>

En cuanto a la página novalido.jsp, su contenido se indica en el siguiente listado:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<f:view>
<h2>Error</h2>
El password <b><h:outputText
value="#{credencialesBean.password}"/>
</b> no es correcto
</f:view>
</body>
</html>

EJERCICIO 1

Seguidamente vamos a realizar una aplicación que permita recoger datos de una
persona y almacenarlos en una colección. así mismo, el programa permitirá al usuario ver los
datos de todas las personas que ha almacenado durante su sesión.

La página de inicio tendrá el aspecto que se indica en la figura 3.

Figura. 3.

El botón “Guardar” almacenará en la colección una nueva persona con los datos
suministrados a través de los campos de texto, permaneciendo después el usuario en la misma
página. Por otro lado, la pulsación del botón “Ver Todos” nos llevará a una nueva página donde
se muestren los datos de todas las personas grabadas por ese usuario, tal y como se indica en
la figura 4.
Figura. 4.

Para empezar, crearemos un bean gestionado llamado PersonaBean que encapsule


los datos de la persona e incluya un método doGuardar() que tenga como misión almacenar los
datos de la nueva persona en un objeto ArrayList. Este objeto será almacenado en un atributo
de sesión para que sea accesible desde todas las peticiones realizadas durante la sesión. El
siguiente listado nos muestra el código de la clase PersonaBean:

package javabeans;
import java.util.*;
import javax.faces.context.FacesContext;
import javax.servlet.http.*;
public class PersonaBean {
private String nombre;
private long telefono;
private int edad;
public PersonaBean() {
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public long getTelefono() {
return telefono;
}
public void setTelefono(long telefono) {
this.telefono = telefono;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}
public String doGuardar(){
FacesContext context=FacesContext.getCurrentInstance();
HttpSession sesion=(HttpSession)context.
getExternalContext().getSession(true);
ArrayList<PersonaBean> listapersonas;
listapersonas=(ArrayList<PersonaBean>)sesion.
getAttribute("listapersonas");
//comprueba si ya existe la colección de personas
//en la sesión y si no es así la crea
if(listapersonas==null){
listapersonas=new ArrayList<PersonaBean>();
sesion.setAttribute("listapersonas",listapersonas);
}
listapersonas.add(this);
return null;
}
}

Podemos observar en la clase anterior como no hemos creado ningún método para
responder a la pulsación del botón “Ver Todos”. El motivo es que este botón simplemente
genera una navegación estática a la página del listado de personas, ver.jsp.

Otro detalle interesante es la devolución del valor null por el método doGuardar(). Esto
es así porque tras ejecutar el método el usuario debe permanecer en la misma página, para lo
que basta con que el método devuelva un valor no definido en ninguno de los elementos
<navigation-case>.

El siguiente listado corresponde al archivo de configuración faces-config.xml, donde


podemos observar el registro de PersonaBean así como las reglas de navegación:

<?xml version='1.0' encoding='UTF-8'?>


<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config
1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
<managed-bean>
<managed-bean-name>PersonaBean</managed-bean-name>
<managed-bean-class>
javabeans.PersonaBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/grabadatos.jsp</from-view-id>
<navigation-case>
<from-outcome>ver</from-outcome>
<to-view-id>/ver.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>

En cuanto a las vistas, el siguiente código corresponde a la página de solicitud de


datos, grabadatos.jsp:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<center><h1>Formulario de datos</h1></center>
<f:view>
<h:form>
<table width="50%" align="center" border="0">
<tr>
<td>Nombre:</td>
<td><h:inputText
value="#{PersonaBean.nombre}"/></td>
</tr>
<tr>
<td>Teléfono:</td>
<td><h:inputText
value="#{PersonaBean.telefono}"/></td>
</tr>
<tr>
<td>Edad:</td>
<td><h:inputText
value="#{PersonaBean.edad}"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<h:commandButton value="Guardar"
action="#{PersonaBean.doGuardar}"/>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<h:commandButton value="Ver Todos"
action="ver"/>
</td>
</tr>
</table>
</h:form>
</f:view>
</html>

Obsérvese como el valor del atributo action del commandButton “Ver Todos” contiene
únicamente la cadena de texto asociada a la página ver.jsp en la regla de navegación.

En cuanto a ver.jsp, se ha utilizado la librería core de JSTL para recorrer la colección


de objetos y mostrar sus propiedades en una tabla HTML. He aquí el código de la página:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<center><h1>Listado de personas</h1></center>
<table border="1" align="center">
<tr>
<th>Nombre</th>
<th>Teléfono</th>
<th>Edad</th>
</tr>
<c:forEach var="per" items="${listapersonas}">
<tr>
<td><c:out value="${per.nombre}"/></td>
<td><c:out value="${per.telefono}"/></td>
<td><c:out value="${per.edad}"/></td>
</tr>
</c:forEach>
</table>
</body>
</html>

EJERCICIO 2

En esta ocasión vamos a realizar un ejercicio que incluya acceso a datos. Se trata de
una página de registro que permita insertar usuarios en una tabla de clientes, tal y como se
indica en la figura 5.

Figura. 5.

Cuando se pulse el botón “Grabar” se procederá a guardar los datos del nuevo cliente
en la base de datos. Si la inserción del registro se ha realizado correctamente, se mostrará una
página con un mensaje indicando dicha circunstancia, sino, se volverá a recargar la misma
página de registro con un mensaje de error en la parte inferior de la misma.

El acceso a los datos lo aislaremos en una clase llamada Operaciones cuyo código se
muestra en el siguiente listado:

package modelo;
import java.sql.*;
import javabeans.*;
public class Operaciones {
public Connection obtenerConexion() {
Connection cn=null;
try{
Class.forName("com.mysql.jdbc.Driver");
cn=DriverManager.getConnection(
"jdbc:mysql://localhost:3306/libreria");
}
catch(Exception e){e.printStackTrace();}
return cn;
}
public boolean insertarCliente(ClienteBean c){
boolean resultado=false;
String sql="Insert into clientes values('";
sql+=c.getUsuario()+"','";
sql+=c.getPassword()+"','";
sql+=c.getEmail()+"',";
sql+=c.getTelefono()+")";
try{
Connection cn=obtenerConexion();
Statement st=cn.createStatement();
st.execute(sql);
cn.close();
resultado=true;
}
catch(Exception e){c.setTextoError(
"error en los datos!");
e.printStackTrace();}
return resultado;
}
}

Por su parte, utilizaremos un bean gestionado al que llamaremos “ClienteBean” para


capturar los datos del nuevo cliente. Este bean, contará además con un método que será
ejecutado como respuesta al comando de acción, y que será el encargado de operar con el
modelo.

A continuación se indica el código de esta clase:

package javabeans;

import modelo.*;
public class ClienteBean {
private String usuario;
private String password;
private String email;
private long telefono;
private String textoError;
public ClienteBean() {
}
public String getUsuario() {
return usuario;
}

public void setUsuario(String usuario) {


this.usuario = usuario;
}

public String getPassword() {


return password;
}
public void setPassword(String password) {
this.password = password;
}

public String getEmail() {


return email;
}

public void setEmail(String email) {


this.email = email;
}

public long getTelefono() {


return telefono;
}

public void setTelefono(long telefono) {


this.telefono = telefono;
}

public String getTextoError() {


return textoError;
}

public void setTextoError(String textoError) {


this.textoError = textoError;
}
public String grabar(){
Operaciones op=new Operaciones();
if(op.insertarCliente(this)){
return "ok";
}
else{
return "mal";
}
}
}

En cuanto a la página de registro, el siguiente listado corresponde al código JSP de la


misma:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>

<f:view>
<h1>Página de registro</h1>
<h:form>
<table>
<tr>
<td>Usuario:</td>
<td><h:inputText
value="#{ClienteBean.usuario}"/></td>
</tr>
<tr>
<td>Password:</td>
<td><h:inputText
value="#{ClienteBean.password}"/></td>
</tr>
<tr>
<td>Email:</td>
<td><h:inputText
value="#{ClienteBean.email}"/></td>
</tr>
<tr>
<td>Teléfono</td>
<td><h:inputText
value="#{ClienteBean.telefono}"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<h:commandButton value="Grabar"
action="#{ClienteBean.grabar}"/>
</td>
</tr>
<h2>
<h:outputText
value="#{ClienteBean.textoError}"/>
</h2>
</table>
</h:form>
</f:view>
</body>
</html>

Obsérvese el uso del tag <h:outputText> para mostrar el mensaje de error.

El siguiente será el listado de la página que se muestra cuando el usuario ha sido


registrado correctamente:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>

<h1>El usuario ha sido registrado correctamente!</h1>

</body>
</html>

En cuanto a faces-context.xml, el siguiente listado muestra el contenido del mismo


donde se refleja el registro del bean y la regla de navegación:

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE faces-config PUBLIC


"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config
1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

<faces-config>
<managed-bean>
<managed-bean-name>ClienteBean</managed-bean-name>
<managed-bean-class>javabeans.ClienteBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/registro.jsp</from-view-id>
<navigation-case>
<from-outcome>ok</from-outcome>
<to-view-id>/registrado.jsp</to-view-id>
</navigation-case>
</navigation-rule>

</faces-config>

4. EVENTOS DE ACCIÓN (ACTIONEVENT)


La activación de un botón o enlace generado mediante un control de comando, además
de provocar el submit de la página genera un evento, conocido como evento de acción al que
se puede asociar un método escuchador en alguna de las clases Java del servidor.

Normalmente, estos métodos escuchadores se codifican en el bean gestionado junto


con los métodos controladores de acción.

Así pues, nos encontramos con que un control de comando puede tener asociado dos
tipos de métodos que serán ejecutados como respuesta a su activación: los controladores de
acción y los escuchadores de acción.

Es importante tener en cuenta las diferencias entre ambos métodos:

Los controladores de acción realizan operaciones de aplicación, relacionadas


con la funcionalidad de esta (aunque normalmente se suele aislar toda la lógica
de negocio en el Modelo), mientras que los escuchadores de acción se utilizan
para realizar algún tipo de actuación sobre la interfaz gráfica. Para ello, los
métodos de escuchadores reciben como parámetro un objeto
javax.faces.event.ActionEvent que proporciona información sobre el componente
que produjo el evento.

Los controles de acción afectan a las reglas de validación, mientras que los
escuchadores no. Un método escuchador no devuelve ningún resultado.
Los escuchadores de acción pueden ser ejecutados antes de procederse a la
validación de los datos (según valor del atributo inmediate), mientras que, como
ya sabemos, los controladores de acción siempre son ejecutados después de
que esta validación se haya realizado.

Para asociar a un control de comando el correspondiente método escuchador, se


emplea el atributo actionListener de la etiqueta correspondiente. Por ejemplo, la siguiente
instrucción genera un commandButton al que asocia el método “limpiar” definido en el bean
“DatosBean”, como respuesta a su evento de acción:

<h:commandButton value=“Reset”
actionListener= “#{DatosBean.limpiar}”/>

El formato del método limpiar sería:

public void limpiar (ActionEvent e){

//código

Mediante el atributo boolean inmediate de commandButton se puede especificar el


momento exacto en que queremos ejecutar el método escuchador. Si su valor es true, la
ejecución se producirá antes de que los datos sean validados, mientras que si es false se
ejecutará después de que los datos hayan sido almacenados en el bean al final del ciclo de
vida de la petición, justo antes de la ejecución del controlador de acción.

4.1. INFORMACIÓN SOBRE EL EVENTO: LAS CLASES ACTIONEVENT Y


UICOMPONENT

Es habitual que desde un método escuchador se quiera acceder a los objetos gráficos
de la interfaz.

Para este fin, el método getComponent() de la clase ActionEvent (método heredado de


la subclase FacesEvent) devuelve un objeto UIComponent que representa el componente
origen del evento.

UIComponent es la clase base de todos los componentes de interfaz de usuario de


JSF. Esta clase dispone un amplio conjunto de métodos con los que podemos acceder a
diversas propiedades gráficas de interés no sólo del componente en el que se ha producido el
evento, sino también del resto de objetos de la interfaz.

Aunque más adelante estudiaremos con más detenimiento la clase UIComponent y sus
subclases específicas correspondientes a los distintos componentes gráficos JSF,
comentaremos a continuación algunos de los métodos más importantes incluidos en esta clase.
Entre ellos se encuentran:

String getId(). Devuelve un String con el valor del atributo id del componente.

UIComponent getParent(). Devuelve el componente padre del objeto.

List getChildren(). Devuelve la colección con todos los hijos del componente.

UIComponent findComponent(String id). Este método intenta localizar en la


misma interfaz un componente cuyo id se especifica. Este método resulta
bastante útil para acceder desde el método manejador de evento al resto de los
componentes del formulario.
void setRendered(boolean render). Establece la propiedad rendered del
componente. Esta propiedad indica si el componente será o no renderizado
(generado dentro de la interfaz) al ser enviada la página al cliente.

Veamos un ejemplo de utilización de eventos de acción en el ejercicio anterior de


almacenamiento y visualización de personas.

La modificación consistirá en hacer inicialmente invisible el botón “Ver Todos” para que
no se pueda acceder a la lista de personas hasta que no se haya guardado al menos una. Al
pulsar el botón “Guardar” se procederá a hacer visible el botón “Ver Todos” la próxima vez que
se muestre la página.

Para hacer invisible inicialmente el botón “Ver Todos” simplemente tenemos que
establecer el valor false en el atributo rendered del componente, así mismo, estableceremos un
valor a su atributo id para poder referirnos después al componente desde código:

<h:commandButton id="vertodos" rendered="false"


value="Ver Todos" action="ver"/>

La visualización del botón la programaremos en el evento ActionListener del botón


“Guardar”:

<h:commandButton value="Guardar"
actionListener="#{PersonaBean.doHabilitar}"
action="#{PersonaBean.doGuardar}" />

Como vemos, se vincula este evento con un nuevo método doHabilitar() definido en la
clase PersonaBean, he aquí el código de este método:

public void doHabilitar(ActionEvent ev){


UIComponent cp=ev.getComponent();
UIComponent btnver=cp.findComponent("vertodos");
btnver.setRendered(true);
}

5. CICLO DE VIDA DEL PROCESAMIENTO DE UNA


PETICIÓN JSF
En este contexto entendemos por ciclo de vida el proceso que tiene lugar desde que el
controlador FacesServlet recibe una petición procedente del navegador cliente hasta que
devuelve la respuesta apropiada.

Es importante tener en cuenta que las fases por las que pase este proceso variaran en
función de si la petición ha sido enviada desde una página generada previamente por el
framework JSP (postback) o no. En este último caso hablaríamos de petición inicial, pues se
refiere a aquellos casos en los que la petición se realiza mediante la introducción de la URL
directamente en el navegador, o al activar un vínculo de alguna página HTML estática.
La figura 6 muestra las diferentes fases que tienen lugar durante el ciclo de vida de la
petición.

Petición
FacesServlet Restore View

Apply Request Values

Process Validations

Update Model Values

Invoke Application

Respuesta
Render Response

Figura. 6.

Tal como se puede apreciar, en el caso que se trate de una petición inicial las fases 2
al 5 serán omitidos, pasando directamente a la última fase encargada de generar la respuesta
al usuario.

Seguidamente analizaremos las acciones que tienen lugar en cada una de estas seis
fases.

5.1. RESTORE VIEW.

Durante esta primera fase, se intenta recuperar el estado del cliente. El estado del
cliente está formado por el conjunto de objetos gráficos UIxxx que forman la interfaz gráfica de
la página desde la que se realiza la petición y que durante la anterior petición fue salvado por el
framework (normalmente en el objeto session), luego este estado solo ha podido ser
almacenado anteriormente si no se trata de una petición inicial.

Lógicamente, en caso de que se trate de una petición inicial el estado anterior no


existirá, procediéndose a crear un nuevo árbol del componentes asociado a la página
solicitada.

El árbol de componentes consta de un objeto raíz UIViewRoot que no está asociado a


ningún elemento visual concreto. De él colgarán los distintos objetos gráficos de la página
(formularios, botones, etc.). La figura 7 muestra un árbol de componentes de ejemplo formado
por tres elementos gráficos.
UIViewRoot

HtmlForm

HtmlCommandButton HtmlTextBoxButton

Figura. 7.

Una vez que se dispone del árbol de componentes (nuevo o recuperado), se procede a
almacenarlo en el contexto de aplicación (FacesContext).

Tras realizar esta operación se pasa a la siguiente fase que, en el caso de una petición
inicial, será la última fase del ciclo (Render Response), mientras que si es un postback será la
siguiente del ciclo (Apply Request Values).

5.2. APPLY REQUEST VALUES

El propósito de esta fase es permitir que el árbol de componentes pueda alimentarse


con los datos procedentes de la petición. Durante esta fase, además, son ejecutados los
métodos escuchadores de evento para todos aquellos componentes en los que el atributo
inmediate se haya establecido al valor true. Para aquellos en los que el valor de dicho atributo
sea false, los eventos generados serán enviados a una cola de la cual serán extraídos durante
la penúltima fase del ciclo para la ejecución de sus métodos escuchadores en el orden
producido.

5.3. PROCESS VALIDATION

Una vez actualizados los valores de los componentes, se procede a la validación de los
datos mediante el procesado de los validadores y conversores asociados a cada componentes
(más adelante veremos el uso de estos elementos).

Si el proceso de validación de alguno de los componentes falla se dará por terminado


el procesamiento de la petición y se pasará a la última fase del ciclo.

5.4. UPDATE MODEL VALUES

Durante esta fase, todos los valores recibidos en la petición y que ya han sido
correctamente validados y convertidos, son asignados a los correspondientes propiedades de
los beans gestionados, según se indica en el atributo value de cada componente gráfico.

Si durante este proceso de asignación se produce algún error, el procesamiento de la


petición se dará por terminado y se pasará a la última fase del ciclo.

5.5. INVOKE APPLICATION

Se procederá a la ejecución de los métodos escuchadores de los eventos encolados,


siguiendo el orden en que dichos eventos se han producido.

Finalmente, se ejecutará el método controlador de acción, cuyo valor de devolución


será utilizado por FacesServlet para determinar la siguiente página a ejecutar, finalizando en
este punto el procesamiento de la petición.
Si el valor devuelto por el método controlador es null, o no coincide con ninguno de los
valores definidos en las reglas de navegación o, simplemente, no existe el método controlador,
se procederá a la ejecución de la siguiente y última fase. En este caso pues, la respuesta que
recibirá el cliente será la propia página desde la que lanzó la petición.

5.6. RENDER RESPONSE

El propósito de esta fase es preparar la respuesta para el usuario, la cual es generada


directamente a partir de las codificaciones definidas por los renderizadores asociados a cada
uno de los componentes del árbol.

Por defecto, cada componente lleva asociado un renderizador que se encarga de


transformar el componente en su correspondiente bloque de etiquetas XHTML. No obstante, a
través del archivo de configuración faces-config.xml pueden especificarse otros kits de
renderización que transformen los componentes en otros formatos.

6. COMPONENTES GRÁFICOS JSF


Es el momento de enfocar nuestro estudio en el conjunto de componentes gráficos
proporcionados por el framework JSF.

La existencia de estos componentes o bloques prefabricados, además de facilitar la


creación de aplicaciones gráficas complejas, permite a los desarrolladores centrarse en la
lógica de aplicación en vez de estar ocupados en las tareas de generación de respuestas. La
figura 8 nos muestra un diagrama con las principales clases de componentes UI de JSF, todas
ellas se encuentran en el paquete javax.faces.component.

UIComponent

UIComponentBase

UIForm UICommand UIOutput UIData UIPanel UIViewRoot

UIInput

UISelectOne UISelectMany UISelectBoolean

Figura. 8.

Una de las principales características del API de componentes de JSF es que


proporciona una gran cantidad de métodos para manipular la interfaz gráfica, sin preocuparnos
por el aspecto concreto que dichos componentes tendrán durante su presentación.

Por eso, aunque mayoritariamente se utilizarán los componentes JSF para la creación
de interfaces basadas en HTML, su uso no está ni mucho menos limitado a este estándar de
presentación; si se dispone del renderizador apropiado, un componente JSF puede adoptar
múltiples formas a la hora de ser presentado.
Esta capacidad de los componentes UI JSF para ser presentados de diferentes formas
es aplicable también incluso dentro de un mismo estándar de presentación. Por ejemplo, el
componente UISelectOne representa un elemento de selección simple, que en el caso concreto
de HTML puede ser implementado como un ListBox de selección simple, un ComboBox o un
conjunto de botones de radio.

6.1. RENDERIZACIÓN

La renderización es el proceso mediante el cual un determinado componente UI es


transformado en un control específico correspondiente a un determinado lenguaje de marcado.

En el caso de los componentes UI JSF, como ya sabemos, la funcionalidad de los


mismos está separada de los detalles de presentación, así, mientras que la funcionalidad es
implementada por el propio componente UI, los detalles de presentación son proporcionados
por el renderizador.

Un renderizador es el objeto que contiene los detalles de presentación de un


determinado tipo de componente, proporcionando los tags apropiados según el lenguaje de
marcado que se vaya a utilizar para la presentación en cliente.

Los renderizadores se encuentran agrupados en lo que se conoce como un kit de


renderización o RenderKit.

Un RenderKit es una colección de renderizadores que utilizan una tecnología común de


presentación para los controles de la interfaz, como por ejemplo HTML.

La especificación JSF proporciona un kit de renderización estándar que incluye un


conjunto de renderizadores para la generación de marcado HTML. Este RenderKit estándar se
encuentra asociado por defecto a cualquier aplicación JSF, de modo serán aplicados sus
renderizadores a la hora de construir la interfaz. No obstante, es posible registrar otros
RenderKits en una aplicación o, incluso, definir kits de renderización personalizados.

En la figura 9 se indican algunas de las clases que utilizan los rederizadores del kit
estándar. Como vemos, se trata de subclases de los componentes UI de JSF que añaden
detalles específicos para la presentación en HTML.

6.2. TAGS DE COMPONENTES JSF

La especificación JSF incluye una librería de acciones o tags JSP para la inclusión de
componentes gráficos JSF dentro de una página JSP. De forma predeterminada, estas
acciones se encuentran asociadas al kit de renderizadores específicos HTML. En la tabla de
figura 10 se muestra la equivalencia entre cada componente HTML y el tag que lo genera.
controles de comando
controles de selección
múltiple controles de texto

UIForm UICommand UIOutput

HTMLForm HTMLCommandButton UIInput


HTMLInputText
HTMLCommandLink
UISelectOne UISelectMany HTMLInputSecret

HTMLInputTextArea

HTMLSelectOneRadio HTMLSelectManyCheckBox

HTMLSelectOneMenu HTMLSelectManyMenu

HTMLSelectOneListBox HTMLSelectManyListBox

controles de selección UISelectBoolean


simple
HTMLSelectBooleanCheckBox

Figura. 9.

Componente HTML Tag JSF Tipo de control

HTMLCommandButton <h:CommandButton..> Botón submit

HTMLCommandLink <h:CommandLink ..> Enlace HTML

HTMLInputText <h:inputText ..> Campo de texto

HTMLInputSecret <h:inputSecret ..> Campo de texto con


caracteres ocultos
HTMLInputTextArea <h:inputTextarea ..> Caja de texto multilínea

HTMLSelectBooleanCheckBox <h:selectBooleanCheckBox ..> Casilla de verificación

HTMLSelectOneRadio <h:selectOneRadio ..> Conjunto de botones de


radio
HTMLSelectOneMenu <hselectOneMenu ..> Lista desplegable

HTMLSelectOneListBox <h:selectOneListbox ..> Lista normal

HTMLSelectManyCheckBox <h:selectManyCheckbox ..> Conjunto de casillas de


verificación
HTMLSelectManyMenu <h:selectManyMenu ..> Lista desplegable de
selección múltiple
HTMLSelectManyListBox <h:selectManyListbox ..> Lista normal de
selección múltiple

Figura. 10.

Seguidamente, vamos a analizar con más detalle cada uno de estos tags, así como las
características de los controles que generan.
6.2.1. Formulario

Todos los componentes gráficos encargados de la captura de datos deben estar


incluidos en un formulario HTML, cuya generación corre a cargo del tag <h:form>. Los valores
de los atributos method y action del formulario se encuentran implícitamente establecidos
POST y a la URL de la página actual, respectivamente. El elemento <h:form> no dispone de
ningún atributo para establecer estos valores, por lo que no podrán ser modificados por el
programador.

En el interior de este elemento se incluirán los tags de controles gráficos.

6.2.2. Controles: atributos comunes.

Hay una serie de atributos que presentan todos los tags para la generación de
controles gráficos y que tienen el mismo significado en todos ellos. He aquí los más
importantes:

id. Identificador del elemento. Representa un identificador único para cada objeto
existente en el formulario. Como ya vimos anteriormente al estudiar alguno de
los métodos de la clase UIComponent, este identificador puede ser utilizado
desde código para referirse a un determinado componente desde métodos como
findComponent().

rendered. Especifica si el control será renderizado inicialmente o no. Tal y como


comprobamos en el ejercicio 2, este atributo puede ser modificado a través del
método serRedered() de cada componente.

6.2.3. Campos de texto

Los campos de texto son componentes de tipo UIInput y se utilizan para solicitar la
entrada de datos al usuario. En una interfaz gráfica HTML podemos utilizar cuatro campos de
texto: Text, Textarea, Secret y Hidden, los cuales son generados por los tags <h:inputText>,
<h:inputTextarea>, <h:inputSecret> e <h:inputHidden>, respectivamente.

Todos estos tags disponen de un atributo value que es utilizado en un doble sentido:

Para asignar un valor inicial al campo a partir de la propiedad de un bean


gestionado.

Para volcar en la propiedad de un bean gestionado el contenido del campo una


vez que se produzca el submit de la página.

Se utilizará la notación EL para indicar en el atributo value la propiedad del bean


implicada en las operaciones anteriores:

<h:inputText value=“#{bean.propiedad}” />

Además del atributo value, estos tags disponen de otro atributo de tipo boolean llamado
required, de modo que si este atributo es true será obligatorio que el usuario suministre un
valor al campo; de no hacerlo, la página será recargada de nuevo y se generará un
mensaje de error. Más adelante, en el capítulo dedicado a los conversores y validadores
analizaremos con detalle este punto.

El valor de este atributo puede ser modificado dinámicamente utilizando e método


setRequired() proporcionado por la clase UIInput.
6.2.4. Controles de comando

Se trata de componentes UICommand cuya misión es, como ya hemos tenido


oportunidad de ver, generar el envío de datos del formulario cuando son activados.

Tenemos dos clases de renderización específica HTML para este componente:


HTMLCommandButton y HTMLLinkButton, que son generados mediante los tags
<h:commandoButton> y <h:linkButton>, respectivamente. Se trata de dos maneras distintas de
realizar esta operación de envío de datos desde la página: mediante la pulsación de un botón o
mediante la activación de un enlace.

Además del atributo value, utilizado para indicar el texto del enlace o botón, estos
controles disponen como atributos más importantes action, actionListener e inmediate, cuyos
significados ya han sido estudiados con anterioridad.

6.2.5. Generación de texto

Se trata de un objeto cuya misión es presentar un texto estático en la página. Se


genera mediante el tag <h:outputText> que corresponde al control HTMLOutputText, subclase
de UIOutput. Mediante el atributo value se establece el texto a mostrar. Este atributo puede
tener dos tipos de valores:

Una cadena de caracteres que represente el texto a mostrar.

Una expresión EL que indique la propiedad del bean cuyo contenido se va a mostrar.
Por ejemplo, el siguiente tag mostraría en contenido de la propiedad mensaje de un bean:

<h:outputText value=“#{ErrorBean.mensaje}” />

6.2.6. Casillas de verificación

La casilla de verificación corresponde a un componente de tipo UISelectOneBoolean y


cuya presentación corre a cargo del tag <h:selectBooleanCheckbox>.

Su atributo value permite vincular el estado del control a una propiedad boolean de un
bean gestionado.

Mediante el método setSelected() de la clase UISelectOneBoolean es posible modificar


el estado del control desde código.

6.2.7. Listas de selección única

La selección de un elemento dentro de un conjunto constituye una funcionalidad típica


de cualquier aplicación Web. Dicha funcionalidad es proporcionada en JSF por el componente
UISelectOne, el cual puede ser renderizado de tres formas diferentes en una página:

Como una lista simple. Representada por el renderizador específico


HTMLSelectOneListbox, es generada mediante el tag <h:selectOneListbox>.

Como una lista desplegable. Representada por el renderizador específico


HTMLSelectOneMenu, es generada mediante el tag <h:selectOneMenu>.

Como un conjunto de botones de radio. Representado por el renderizador


específico HTMLSelectOneRadio, es generado mediante el tag
<h:selectOneRadio>.
Los tres tags disponen de un atributo value que permite indicar la propiedad del bean
gestionado donde será almacenado el valor del elemento seleccionado, una vez se produzca el
submit de la página.

6.2.7.1. Componentes de una lista

Los elementos contenidos una lista de selección son objetos de tipo


javax.faces.model.SelectItem. Cada uno de estos objetos encapsula el valor y el texto a
mostrar del elemento que representa.

Existen dos maneras de indicar durante la fase de diseño de la aplicación el conjunto


de objetos SelectItem que formará la lista:

Mediante componentes UISelectItem. Cada componente UISelectItem genera


un elemento SelectItem. Los componentes UISelectItem son incluidos dentro de
la lista mediante el tag <f:selectItem>. Cada tag de este tipo dispone de dos
atributos:

- itemLabel. Texto que se va a mostrar para el elemento.

- itemValue. Valor asociado al elemento.

Así pues, deberán anidarse tantos <f:selectItem> dentro del tag que genera la
lista como elementos vaya a contener ésta. El siguiente bloque crearía un
ListBox en la página con los días laborables de la semana:

<h:selectOneListbox id="lista">
<f:selectItem itemLabel="lunes" itemValue="1"/>
<f:selectItem itemLabel="martes" itemValue="2"/>
<f:selectItem itemLabel="miércoles" itemValue="3"/>
<f:selectItem itemLabel="jueves" itemValue="4"/>
<f:selectItem itemLabel="viernes" itemValue="3"/>
</h:selectOneListbox>

Como podemos observar, esta forma de generar una lista de opciones es


adecuada cuanto el contenido de la lista es estático (no será modificado) y es
conocido durante la fase de diseño de la aplicación.

Mediante un componente UISelectItems. Cuando el contenido de la lista va a


ser generado de forma dinámica podemos hacer uso de este componente, cuya
función es la de crear un conjunto de objetos SelectItem dentro de la lista. El
componente UISelectItems se genera con el tag <f:selectItems> que, mediante
su atributo value, deberá indicar la propiedad del bean gestionado donde está
contenido el conjunto de objetos SelectItem. Este conjunto puede ser tanto un
array como una colección de objetos SelectItem.

Por ejemplo, las siguientes tags generarían un conjunto de botones de radio con
las opciones disponibles en una colección de objetos SelectItem almacenada en
la propiedad “turnos” del bean CursosBean:

<h:selectOneRadio value="#{CursosBean.seleccionado}" >


<f:selectItems value="#{CursosBean.turnos}"/>
</h:selectOneRadio>
Por su parte, el bloque de código que genera el contenido de la propiedad turnos
del bean podría estar implementado de la siguiente manera:

class CursosBean{
private List<SelectItem> turnos;
:
public CursosBean(){
turnos = new ArrayList<SelectItem>();
turnos.add(new SelectItem(0, “mañana”));
turnos.add(new SelectItem(1, “tarde”));
turnos.add(new SelectItem(2, “noche”));
}
:
public List<SelectItem> getTurnos(){
return turnos;
}
:
}

Podemos observar como durante la creación del los objetos SelectItem se pasa
como parámetros al constructor, en este orden, el valor asociado al elemento y el
texto a mostrar.

6.2.8. Listas de selección múltiple

La funcionalidad de las listas de selección múltiple es suministrada por el componente


UISelectMany, pudiendo ser renderizado de tres formas diferentes en una página:

Como una lista de selección múltiple. Representada por el renderizador


específico HTMLSelectManyListbox, es generada mediante el tag
<h:selectManyListbox>.

Como una lista de selección múltiple y una línea de altura. En cuanto a


tamaño es similar a las listas desplegables, si bien se muestra siempre abierta
con dos flechas para realizar desplazamientos arriba y abajo. Está representada
por el renderizador específico HTMLSelectManyMenu, que es generado
mediante el tag <h:selectManyMenu>.

Como un conjunto de casillas de verificación. Representado por el


renderizador específico HTMLSelectManyCheckbox, es generado mediante el
tag <h:selectManyCheckbox>.

El atributo value deberá especificar la propiedad del bean donde se almacenarán los
valores de los elementos seleccionados. En este caso, dicha propiedad tendrá que ser de tipo
array o colección.

En cuanto a la creación del contenido de la lista, se utilizan exactamente las mismas


técnicas que en las listas de selección simple.
6.3. EL EVENTO VALUECHANGEEVENT

El evento ValueChangeEvent se produce en todos los componentes de tipo UIInput,


como las listas simples, listas desplegables o cajas de texto y tiene lugar cuando se produce un
cambio en el dato de entrada del componente. Por ejemplo, en el caso de las cajas de texto
este evento se produce cada vez que se modifica el contenido del campo, mientras que en las
listas se produce al seleccionar un nuevo elemento.

A diferencia de ActionEvent, el evento ValueChangeEvent no produce el submit de


la página; todos los eventos de este tipo producidos en los distintos componentes de la interfaz
quedan añadidos a una cola para después proceder a la ejecución de sus métodos de
respuesta una vez que se lance la petición al servidor.

Al igual que sucede con ActionEvent, los métodos de respuesta a los eventos
ValueChangeEvent pueden ser codificados en alguno de los beans gestionados. Estos
métodos deberán tener el formato:

public void metodoRespuesta(ValueChangeEvent ev)

A través de las propiedades del objeto ValueChangeEvent podemos acceder a


información de interés sobre el evento. Entre ellas destacan:

getComponent(). Al igual que en ActionEvent, nos devuelve una referencia al


componente donde se ha producido el evento.

getOldValue(). Devuelve el valor anterior del componente, antes de producirse


el evento.

getNewValue(). Devuelve el nuevo valor del componente.

Por otro lado, la vinculación entre el control y el método manejador de evento


correspondiente se realizará a través del atributo valueChangeListener del tag. El siguiente
ejemplo asociaría el evento de cambio de turno al método actualiza() del bean CursosBean:

<h:selectOneRadio value="#{CursosBean.seleccionado}"
valueChangeListener="#{CursosBean.actualiza}">
<f:selectItems value="#{CursosBean.turnos}"/>
</h:selectOneRadio>

EJERCICIO 3

En este ejercicio vamos a desarrollar una aplicación para una tienda de ordenadores,
consistente en una página de inicio que permita al usuario configurar su equipo, permitiéndole
elegir un módulo de memoria de una lista y una serie de accesorios adicionales, tal y como se
indica en la figura 11.
Figura. 11.

Así mismo, se le permitirá indicar la forma de pago elegida, de modo que si elige
“transferencia” se le aplicará un descuento en el precio final de un 10%.

Al pulsar calcular se mostrará en una nueva página el precio final según la


configuración elegida (figura 12).

Figura. 12.

Hay que tener en cuenta que se parte de un precio base de 300 euros, al que habrá
que añadir los precios de la memoria y los accesorios, los cuales están almacenados en una
base de datos.

Inicialmente, crearemos una clase que formará parte del modelo, encargada de obtener
las listas de precios para poder vincularlas a los controles de lista. Esta clase que llamaremos
PreciosBean corresponderá al siguiente listado:

package javabeans;

import java.util.*;
import javax.faces.model.*;
import java.sql.*;
public class PreciosBean {
private List<SelectItem> memoria;
private List<SelectItem> accesorios;
public Connection obtenerConexion() {
Connection cn=null;
try{
Class.forName("com.mysql.jdbc.Driver");
cn=DriverManager.getConnection("
jdbc:mysql://localhost:3306/ordenadores");
}
catch(Exception e){e.printStackTrace();}
return cn;
}
public List<SelectItem> getMemoria(){
//obtiene la lista de precios de los
//módulos de memoria
String sql="";
ArrayList<SelectItem> totales=
new ArrayList<SelectItem>();
try{
Connection cn=obtenerConexion();
Statement st=cn.createStatement();
sql="SELECT capacidad, precio FROM memoria";
ResultSet rs=st.executeQuery(sql);
while(rs.next()){
totales.add(new SelectItem(
rs.getString("precio"),rs.getString("capacidad")));
}
cn.close();
}
catch(Exception e){e.printStackTrace();}
finally{memoria=totales;return memoria;}
}
public List<SelectItem> getAccesorios(){
//obtiene la lista de precios de los
//accesorios
String sql="";
ArrayList<SelectItem> totales=
new ArrayList<SelectItem>();
try{
Connection cn=obtenerConexion();
Statement st=cn.createStatement();
sql="SELECT nombre, precio FROM accesorios";
ResultSet rs=st.executeQuery(sql);
while(rs.next()){
totales.add(new SelectItem(
rs.getString("precio"),rs.getString("nombre")));
}
cn.close();
}
catch(Exception e){e.printStackTrace();}
finally{accesorios=totales; return accesorios;}
}

public void setMemoria(List<SelectItem> memoria) {


this.memoria = memoria;
}

public void setAccesorios(List<SelectItem> accesorios) {


this.accesorios = accesorios;
}
}
Por otro lado, la clase bean que capturará la configuración elegida, a la que llamaremos
ConfiguracionBean, tendrá el siguiente código:

package javabeans;

import javax.faces.event.*;
import javax.faces.component.*;
import javax.faces.component.html.*;
public class ConfiguracionBean {

private String preciomemoria;


private String[] precioaccesorios;
private String envio;
private double preciofinal=300;
private String datosconfiguracion;

public String getPreciomemoria() {


return preciomemoria;
}

public void setPreciomemoria(String preciomemoria) {


this.preciomemoria = preciomemoria;
}

public String[] getPrecioaccesorios() {


return precioaccesorios;
}

public void setPrecioaccesorios(String[] precioaccesorios) {


this.precioaccesorios = precioaccesorios;
}

public String getEnvio() {


return envio;
}

public void setEnvio(String envio) {


this.envio = envio;
}

public String getDatosconfiguracion() {


return datosconfiguracion;
}

public void setDatosconfiguracion(String datosconfiguracion)


{
this.datosconfiguracion = datosconfiguracion;
}

public String calcular(){


setPreciofinal(getPreciofinal()+Integer.parseInt(
this.getPreciomemoria()));
for(String p:this.precioaccesorios){
setPreciofinal(getPreciofinal() +
Integer.parseInt(p));
}
if(Integer.parseInt(envio)==1){
setPreciofinal(getPreciofinal() * 0.9);
}
return "resultado";
}
public double getPreciofinal() {
return preciofinal;
}

public void setPreciofinal(double preciofinal) {


this.preciofinal = preciofinal;
}

Seguidamente se muestran los listados con las vistas de la aplicación:

index.jsp

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<f:view>
<h:form>
<h1>Configuración de Equipo Informático</h1>
<br/><br/>
<table>
<tr>
<td><b>Memoria:</b></td>
<td><h:selectOneMenu id="memoria"
value="#{ConfiguracionBean.preciomemoria}">
<f:selectItems
value="#{PreciosBean.memoria}"/>
</h:selectOneMenu></td>

<td><b>Accesorios:</b><br/></td>
<td><h:selectManyCheckbox id="accesorios"
value="#{ConfiguracionBean.precioaccesorios}">
<f:selectItems
value="#{PreciosBean.accesorios}"/>
</h:selectManyCheckbox</td>
</tr>
<tr>
<td><br/><b>Forma de pago:</b></td>
<td><br/><h:selectOneRadio id="pago"
value="#{ConfiguracionBean.envio}">
<f:selectItem itemLabel="Transferencia"
itemValue="1"/>
<f:selectItem itemLabel="Contra
reembolso" itemValue="2"/>
</h:selectOneRadio></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="4" align="center"><br/>
<h:commandButton value="Calcular"
action="#{ConfiguracionBean.calcular}"/>
</td>
</tr>
</table>
</h:form>
</f:view>

</body>
</html>

resultado.jsp

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<f:view>
<h1>Configuración elegida</h1>

<br/><br/>
<h3>El precio final es de: <h:outputText
value="#{ConfiguracionBean.preciofinal}"/> eur.</h3>
</f:view>

</body>
</html>

7. CONVERSORES Y VALIDADORES
El proceso de conversión y validación de datos es una tarea sumamente importante
dentro de una aplicación Web, pues tiene como objetivo adaptar la información suministrada
por el usuario mediante los campos de la interfaz a los tipos y características de los datos
manejados por la aplicación.

Como tuvimos oportunidad de ver durante el análisis del ciclo de vida de una petición
JSF, este proceso tiene lugar durante la segunda fase del ciclo llamada Proccess Validation.
Según se indicó entonces, cualquier error en la validación o conversión de alguno de los
campos producirá el fin del procesado de la petición y la recarga de la página desde la que se
lanzó la petición, indicando se en la misma los mensajes de error generados durante el
proceso.

Seguidamente vamos a analizar de manera independiente las distintas técnicas que


nos ofrece la tecnología JSF para realizar las conversiones y validaciones de datos en una
aplicación.

7.1. VALIDADORES

La validación de datos consiste en comprobar la validez de un campo de entrada antes


de proceder a la asignación del mismo a la propiedad del bean correspondiente.

Dejando a un lado la validación manual de datos que siempre podríamos incluir en los
métodos set del JavaBean, JSF nos ofrece la siguientes técnicas de validación de datos:

Validación automática.

Utilización de validadores implícitos JSF.

Métodos de validación personalizados.

7.1.1. Validación automática

La validación automática no requiere ninguna acción por parte del programador,


aunque afecta únicamente a los tipos de datos y a la obligatoriedad de incluir valores en los
campos.

Por ejemplo, si un determinado campo está asociado a una propiedad int de un bean,
JSF intentará realizar la conversión de los caracteres introducidos a int. Si algún carácter no es
numérico, se producirá un error de validación en el campo.

En cuanto a la obligatoriedad de incluir valores en un campo, todos los tags que


generan componentes UIInput disponen de un atributo llamado required, de modo que si éste
está establecido a true será obligatorio introducir un valor en el campo. Si el usuario deja
en blanco un campo de estas características se detectará este hecho durante la fase Process
Validator y se procederá a abortar el procesado de la petición, recargándose de nuevo la
página en el cliente.

Cada vez que se detecta un error de validación, el entorno JSF genera un mensaje de
error que puede ser mostrado en el momento que vuelva a recargarse la página mediante el
tag <h:message>. Este tag incluye un atributo llamado for en el que se debe especificar el id
del control cuyo mensaje de error se quiere mostrar.

Por ejemplo, supongamos que en el formulario utilizado en el ejercicio 1 queremos


establecer la obligatoriedad por parte del usuario de introducir datos en los tres campos
utilizados. El código fuente de la página grabadatos.jsp quedaría como se indica en el siguiente
listado:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<center><h1>Formulario de datos</h1></center>
<f:view>
<h:form>

<table width="50%" align="center" border="0">


<tr>
<td>Nombre:</td>
<td><h:inputText id="nombre" required="true"
value="#{PersonaBean.nombre}"/></td>
<td><h:message for="nombre"/></td>
</tr>
<tr>
<td>Teléfono:</td>
<td><h:inputText id="tel" required="true"
value="#{PersonaBean.telefono}"/></td>
<td><h:message for="tel"/></td>
</tr>
<tr>
<td>Edad:</td>
<td><h:inputText id="edad" required="true"
value="#{PersonaBean.edad}"/></td>
<td><h:message for="edad"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<h:commandButton value="Guardar"
actionListener="#{PersonaBean.doHabilitar}"
action="#{PersonaBean.doGuardar}" />
</td>
</tr>
<tr>
<td colspan="2" align="center">
<h:commandButton id="vertodos"
rendered="false" value="Ver Todos"
action="ver"/>
</td>
</tr>
</table>
</h:form>
</f:view>
</html>

Podemos ver como además de añadir el atributo required con el valor true a cada uno
de los campos de texto, hemos incluido una celda al lado de cada campo donde se mostrará el
mensaje de error asociado al mismo en caso de no cumplirse el criterio de validación. La figura
13 muestra el aspecto de la página en caso de intentar el envío de datos sin haber introducido
ningún valor en el campo “nombre”.

Los mensajes de error mostrados están definidos dentro de un archivo de recursos


llamado Message.properties que se encuentra en la librería jsf-impl.jar de JSF.

Figura. 13.

Es posible definir nuestros propios mensajes de error personalizados, para ello


crearíamos un archivo .properties con la estructura de Message.properties y lo situaríamos en
el directorio WEB-INF\classes de la aplicación Web. El nombre de ese archivo puede ser
cualquiera, pero para que la aplicación haga uso del mismo en vez de Message.properties
sería necesario añadir la siguiente entrada en faces-config.xml:

<application>
<message-bundle>Nombre_archivo</message-bundle>
</application>
Donde Nombre_archivo será el nombre del archivo de recursos sin la extensión
.properties.

La validación automática también se aplica como hemos dicho a los tipos de datos de
los campos. Por ejemplo, si en la página anterior se introduce un valor que incluye caracteres
no numéricos en el campo edad, se producirá un error de conversión de tipos (recordemos que
el campo edad está definido como int en el bean PersonaBean), recargándose de nuevo la
página con el aspecto indicado en la figura 14.

Figura. 14.

7.1.2. Validadores implícitos JSF

La especificación JSF incluye una serie de validadores que permiten realizar


comprobaciones clásicas en los campos de un formulario.

Estos validadores son clases que implementan la interfaz


javax.faces.validator.Validator, en las JSF delega la comprobación de ciertas características de
los campos.

Para utilizar uno de estos validadores sobre un determinado campo, tan solo
tendremos que anidar el tag asociado al validador dentro del campo a validar. El siguiente
ejemplo utiliza un validador JSF que comprueba que el número de caracteres del campo
“codigo” sea como mínimo 4:

Código: <h:inputText id="codigo" value="#{DatosBean.codigo}">


<f:validateLength minimum="4"/>
</h:inputText>
<h:message for="codigo"/>

Al igual que con las validaciones implícitas, utilizamos el tag <h:message> para indicar
el lugar donde se debe mostrar el mensaje de error en caso de incumplirse los criterios de
validación.

Tres son los validadores proporcionados por la especificación JSF. Las clases que
incluyen la lógica para la realización de las validaciones se encuentran en el paquete
javax.faces.validator, sin embargo, el programador no tendrá que encargarse de instanciar
estas clases e invocar a los métodos de validación, todo ello se hace automáticamente, como
hemos visto antes, anidando dentro del campo a validar el tag de validación apropiado. Estos
tags se incluyen en la librería f de JSF y son:

<f:validateLength>. Comprueba que el número de caracteres introducido en el


campo se encuentra dentro de un determinado rango. Mediante los atributos
minimum y maximum se especifica el número mínimo y máximo de caracteres,
respectivamente, que debe tener el dato introducido. Ambos atributos son
opcionales, por lo que puede establecerse únicamente un límite inferior o
superior.

<f:validateLongRange>. Comprueba que el valor numérico entero introducido en


el campo esté dentro de un determinado rango. Rango que será determinado por
los atributos minimum y maximum de la etiqueta. Como en el tag anterior, ambos
valores son opcionales.

<f:validateDoubleRange>. Comprueba que el valor numérico introducido en el


campo esté dentro de un determinado rango. En este caso, el valor del campo
será interpretado como double. El rango de valores viene determinado, como en
los tags anteriores mediante los atributos minimum y maximum.

En los tres casos, cuando el código de validación determine que el valor introducido
no cumple con los criterios definidos se lanzará una excepción ValidationException que
provocará la recarga de la página y la visualización de los mensajes de error en los lugares
definidos por <h:message>

7.1.3. Validadores personalizados

Cuando los criterios de validación de los validadores JSF no se ajustan a los


requerimientos de un determinado campo, será necesario definir nuestros propios métodos de
validación personalizados en los que incluiremos el código necesario para realizar las
comprobaciones requeridas.

Estos métodos podrán ser definidos en los beans gestionados utilizados por la
aplicación. Podrán ser llamados de cualquier manera, si bien deberán ajustarse al siguiente
formato:

public void nombre_metodo(FacesContext context,


UIComponent component,
Object value) throws ValidatorException

Además de no devolver ningún resultado, deberán declarar tres parámetros cuyo


significado será el siguiente:

context. Objeto FacesContext asociado a la aplicación.

component. Componente gráfico a validar.

value. Valor que debe ser validado.

Estos tres parámetros son pasados por el entorno de ejecución de JSF al método
durante la fase de validación de datos (Process Validation).

En el interior de este método se incluirá el código necesario para realizar las


comprobaciones, según los criterios que hayamos establecido. En caso de que dichos criterios
no se cumplan, el método deberá lanzar una excepción de tipo
java.faces.validator.ValidatorException.
Por otro lado, para vincular un componente UI con el método de validación
personalizado simplemente debemos indicar la referencia al mismo, utilizando la notación EL,
en el atributo validator del tag del elemento.

El siguiente bloque JSP de ejemplo incluye un campo “email” dentro de una página, al
que asocia un método de validación definido en el bean “DatosBean”:

Email: <h:inputText id="email" value="#{DatosBean.email}"


validator="#{DatosBean.compruebaemail}"/>
<h:message for="email"/>

El método compruebaemail podría estar definido de la siguiente manera en DatosBean:

public void compruebaemail(FacesContext context,


UIComponent component,
Object value) throws ValidatorException{
String valor=(String)value;
if((valor.indexOf("@")==-1)||(valor.indexOf(".")==-1)){
throw new ValidatorException(
new FacesMessage("Email no valido"));
}
return;
}

Observamos en el código de ejemplo anterior como el constructor de la clase


ValidatorException requiere como parámetro un objeto javax.faces.application.FacesMessage
que representa un mensaje de validación. De los cuatro constructores incluidos en la clase
FacesContext, el que se utiliza en este ejemplo recibe como parámetro un String
correspondiente a mensaje resumido de error, mensaje que será mostrado por el tag
<h:message>.

7.2. CONVERSORES

La misión de los conversores es doble, por un lado se encargan de realizar una


conversión de los datos suministrados por el usuario a través de los campos, a fin de
adaptarlos a las características requeridas por la aplicación.

Por otro lado, los conversores permiten realizar una conversión en sentido contrario,
formateando los datos utilizados por la aplicación para que puedan ser adecuadamente
presentados en la página. Por ello, a diferencia de los validadores que, únicamente pueden ser
utilizados con componentes de entrada de datos, los conversores pueden ser empleados
tanto con componentes de entrada como de salida, es decir, con cualquier componente
UIOutput.

Además de las conversiones implícitas realizadas por JSF para adaptar los contenidos
de los campos a los tipos definidos por las propiedades del bean asociado, la especificación
JSF incluye una serie de conversores que podemos utilizar en cualquier aplicación.
7.2.1. Conversores implícitos JSF

Se trata de un conjunto de clases incluidas en el paquete javax.faces.convert que


permiten realizar conversiones en forma bidireccional de los datos. Como sucede con los
validadores, JSF incluye una serie de tags en la librería “f” que, anidados dentro del campo
correspondiente, permiten hacer uso de las clases conversoras durante la fase de diseño.

El siguiente ejemplo formatea el contenido del campo “salario” como tipo moneda. De
esta manera será en este formato como se presentará en el campo de texto el contenido de la
propiedad “salario” del bean y, por otro lado, cualquier valor introducido en dicho campo será
convertido a formato moneda al realizar el envío de la página, antes de ser asignado a la
propiedad:

Salario: <h:inputText id="salario"


value="#{EmpleadoBean.salario}">
<f:convertNumber type="currency"/>
</h:inputText>

Los dos tags proporcionados por JSF para la conversión y formato de datos son:

<f:convertNumber>. Es el que hemos utilizado en el ejemplo anterior; se utiliza


para realizar operaciones de formato de valores numéricos. Entre los atributos
más importantes de este tag destacamos:

- type. Especifica el tipo de formato del número. Sus posibles valores


son “currency”, “percentage” y “number”, siendo este último el valor
predeterminado.

- integerOnly. Si está establecido a true, únicamente se almacenará en


la propiedad la parte entera del valor introducido en el campo. Así
mismo, este sólamente mostrará la parte entera de la propiedad.

- minFractionDigits. Indica el número mínimo de decimales con el que


será formateado el número.

- maxFractionDigits. Indica el número máximo de decimales con el que


será formateado el número. Por ejemplo, si este atributo está
establecido al valor 2 y en el campo se introduce 234,3457, el valor
asignado a la propiedad (suponiendo que sea de tipo decimal) será
234,34.

- minIntegerDigits. Mínimo número de dígitos con el que será


formateada la parte entera.

- manFractionDigits. Máximo número de dígitos con el que será


formateada la parte entera. Por ejemplo, si el atributo está establecido
al valor 2 y en el campo se introduce el número 123,45, el primer dígito
entero será desechado, almacenándose el valor 23,45 en la propiedad.

- currencySymbol. Símbolo utilizado para formatear el dato cuando se


utiliza el tipo “currency”.

- pattern. Cadena de caracteres que define un patrón de formato


personalizado. Si este atributo se encuentra establecido, se ignorará
el contenido del atributo type. Podemos encontrar información sobre
los caracteres de formato en la ayuda sobre la clase
java.text.NumberFormat. Por ejemplo, en el siguiente ejemplo se
formatearía el campo “salario” como un número con una única cifra
decimal:

salario: <h:inputText id="salario"


value="#{DatosBean.salario}">
<f:convertNumber pattern="##.#"/>
</h:inputText>

Si se introduce el valor 234,7967, será formateado como 234,8.

<f:convertDateTime>. Se emplea para realizar operaciones de formato de


fechas y horas. Sus principales atributos son:

- type. Especifica el tipo de formato a aplicar. Sus posibles valores son


“date”, “time” o “both”.

- dateStyle. Especifica el estilo del formato para fechas. Sus posibles


valores son “default”, “short”, “medium” o “long”. El siguiente ejemplo
se establece un formato de fecha corta para el campo “fecha
nacimiento”:

fecha nacimiento <h:inputText id="fecha"


value="#{DatosBean.fecha}">
<f:convertDateTime type="date" dateStyle="short"/>
</h:inputText>

- timeStyle. Especifica el estilo del formato para la hora. Sus posibles


valores son “default”, “short”, “medium” o “long”.

- pattern. Especifica un patrón de formato personalizado para la


fecha/hora. En la clase java.text.DateFormat podemos encontrar
información sobre los posibles caracteres de formato a utilizar. Si este
atributo se encuentra especificado, se ignorará el contenido de los
atributos dateStyle, timeStyle y type.

- timeZone. Cadena de caracteres que representa la zona horaria con la


que será formateada la fecha/hora. Por ejemplo, si la propiedad “fecha”
del bean DatosBean contiene la fecha/hora actuales, el siguiente tag
mostrará en la página la fecha actual en la zona de Los Ángeles
formateada con formato corto:

Hora en Los Angeles: <h:outputText id="fecha"


value="#{DatosBean.fecha}">
<f:convertDateTime timeZone="America/Los_Angeles"
type="time" timeStyle="short"/>
</h:outputText>
AUTOEVALUACIÓN

1. Un objeto FacesServlet pertenece a la capa:

A. Controlador

B. Vista

C. Modelo

D. Es un elemento de apoyo a las tres capas anteriores

2. Indica cual de las siguientes características no es


aplicable al framework JSF:

A. Las aplicaciones son conducidas por eventos

B. Permite crear aplicaciones bajo arquitectura MVC

C. Los componentes gráficos JSF únicamente pueden ser


utilizados en páginas JSP

D. La navegación entre páginas se define en el archivo


de configuración faces-config.xml

3. La ejecución de los métodos de respuesta a los eventos


ActionEvent de una interfaz JSF se produce en la fase:

A. Restore View

B. Apply Request Values

C. Invoke Application

D. Depende del atributo inmediate del componente

4. El acceso a los atributos de sesión desde un método


controlador de acción se realiza:

A. A través del objeto ActionEvent recibido como


parámetro

B. A través de la clase FacesContext

C. A través de la clase FacesServlet

D. Utilizando las propiedades de los beans gestionados


5. Tenemos un bean gestionado de identificador ComprasBean
que incluye un método llamado listado() que recupera un
conjunto de filas de una base de datos y las almacena
en un atributo de petición, devolviendo como resultado
una cadena de texto que servirá para determinar la
próxima vista a enviar al usuario. Si queremos que ese
método sea ejecutado al pulsar un botón de comando
linkCommand, ¿cual de las siguientes acciones
deberíamos incluir en una página JSP para realizar esa
operación?:

A. <h:linkButton value="Aceptar"

actionListener="#{ComprasBean.listado}"/>

B. <h:linkButton value="Aceptar"

actionListener="#{ComprasBean.listado}"

inmediate="true"/>

C. <h:linkButton value="Aceptar"

action="#{ComprasBean.listado}"/>

D. <h:linkButton label="Aceptar"

value="#{ComprasBean.listado}"/>

6. Indica cual de las siguientes acciones JSP serviría


para generar una lista de selección múltiple:

A. <h:selectOneMenu>
<f:selectItems value="#{LibrosBean.libros}"/>
</h:selectOneMenu>

B. <h:selectManyMenu>
<f:selectItems value="#{LibrosBean.libros}"/>
</h:selectManyMenu>
C. <h:selectOneListbox multiple="true">
<f:selectItems value="#{LibrosBean.libros}"/>
</h:selectOneListbox>
D. <h:selectManyListbox>
<f:selectItems value="#{LibrosBean.libros}"/>
</h:selectManyListbox>
7. ¿Cual de los siguientes controles no es de tipo
UIInput?

A. Lista de botones de radio

B. Botón de pulsación

C. Caja de texto simple

D. Caja de texto multilínea

8. Para forzar a que el dato introducido por el usuario


tenga un número de caracteres contenido en un
determinado rango debemos utilizar:

A. El validador <f:validateLength>

B. El validador <f:validateLongRange>

C. El validador <f:textRange>

D. Un validador personalizado
Ejercicios Propuestos

1. Crear una nueva versión del ejercicio 2 resuelto en el tema de servlets,


consistente en generar dinámicamente una página formateada según las opciones
indicadas en una página HTML:

Figura. 15.

Al pulsar el botón generar los datos serán enviados a una página JSP que será la
encargada de generar dinámicamente la nueva página según las opciones
elegidas. En este caso, emplearemos controles JSF para diseñar la interfaz y
realizaremos la gestión de eventos que consideremos adecuada.

2. Incluir los validadores necesarios en la página de registro del ejercicio 2, de forma


que se deban cumplir los siguientes criterios:

i. Todos los campos serán de obligada cumplimentación.

ii. El nº de caracteres del campo password será como mínimo de 4 y


como máximo de 8.

iii. El campo email debe ser válido (incluirá un punto y la @)

iv. El campo teléfono debe incluir solo caracteres numéricos.

Se deberán mostrar los mensajes de error en cada campo que incumpla las reglas
de validación.

3. Crear una nueva versión de la aplicación para la realización de votaciones a


través de Internet realizada en temas anteriores, basada en este caso en la
utilización del framework JSF.
4. Realizar una aplicación de librería, donde un usuario pueda ser validado a través
de una página de login que además contará con un enlace a una página de
registro para que se puedan registrar en caso de no estarlo.

Una vez validado, se mostrará una página con una lista desplegable para la
selección del tema, de modo que al seleccionar uno de ellos se visualicen, en la
misma u otra página, todos los libros de ese tema.

La aplicación se desarrollará siguiendo el patrón MVC y con framework JSF. Y


deberá incluir gestión de eventos y validación de datos.

Utilizar como tablas de datos las empleadas en otros ejercicios realizados durante
el curso.

Das könnte Ihnen auch gefallen