Tutorial JSF 2.2 - Sesión 3: Ciclo de vida de una aplicación
Siguiendo con el tutorial de JSF 2.2, esta vez veremos el ciclo de vida de una aplicación. Es importante conocer esto, ya que podremos saber cómo viaja una petición desde el cliente web, es procesado por el servidor, y cómo devuelve el resultado.
En la página 7.6 The Lifecycle of a JavaServer Faces Application se puede ver el siguiente gráfico que representa el ciclo de vida de una aplicación:
... pero como no quiero dar una simple traducción de otra web, lo que haremos es ver cada fase del ciclo de vida en una aplicación.
Fijémonos en los recuadros azules, son seis. Estos son los pasos que se ejecuta en el lado del servidor. Los recuadros blancos son como los "estímulos" para que la aplicación haga algo. Como podemos ver en el flujo, puede pasar desde los primeros recuadros "Restore View" y "Apply Request" hasta "Process Validations" si es que se aplica una validación, o puede ir directo a la última fase "Render Response" si es que no tiene nada que hacer. Esto último sucede cuando se llama a una página por primera vez y no se procesa nada, mas que mostrar el contenido de la página.
Para probar eso, vamos a crear una aplicación (que yo la llamé jsf-03-lifecycle) y tiene los siguientes
Nuestro ManagedBean tendrá el siguiente código:
El bean que nos servirá de bean tiene el siguiente código:
Hasta aquí no hay nada extraordinario. Ahora debemos agregar un "oidor" que lo engancharemos al ciclo de vida para ver los efectos que sucede cuando ejecutamos la aplicación.
Y para engancharlo al ciclo de vida de la aplicación, debemos crear el archivo
Una vez creado, registramos el listener en el .xml que acabamos de crear usando el siguiente código:
Ahora, ejecutaremos la aplicación, y veamos el log de cada petición que hagamos.
Veamos: La primera vez que ejecutamos:
Solo se presentan dos fases: RESTORE_VIEW y RENDER_RESPONSE. Es decir, la primera y la última fase.
Veamos qué pasa cuando colocamos valores y le damos clic en "Enviar":
Al parecer ya pasa por todas las fases del ciclo de vida. Veamos si ponemos una validación. Para ello agregamos las líneas resaltadas en el
Y creamos la siguiente clase:
Y al ejecutar el proyecto, ingresemos un valor no válido para el correo electrónico. Esto es lo que nos mostrará en el log del servidor:
(He limpiado el log antes de ejecutar el error. Esto es para poder más claramente el log que responde)
Como podemos ver, no muestra el paso 4 ni el paso 5. Es decir, no está actualizando el modelo, ni está dando la ejecución a la aplicación, ya que la validación no lo dejó.
De esta manera, nos podemos asegurar que cada fase se ejecuta de manera independiente, y no afecta con la lógica de nuestra aplicación. Si queremos validar una entrada de un campo, debemos asegurarnos que se haga en su capa respectiva (usando los validadores) y no cuando haya guardado los valores en el modelo, ya que sería más difícil el manejo de mensajes de error al usuario. Con esto en mente, veremos poco a poco como este ciclo de vida nos ayudará en las siguientes aplicaciones.
Esto es todo por ahora.
El código fuente lo pueden descargar desde aquí: https://java.net/projects/apuntes/downloads/download/web/Tutorial%20JSF%202.2/jsf-03-lifecycle.tar.gz
En la página 7.6 The Lifecycle of a JavaServer Faces Application se puede ver el siguiente gráfico que representa el ciclo de vida de una aplicación:
... pero como no quiero dar una simple traducción de otra web, lo que haremos es ver cada fase del ciclo de vida en una aplicación.
Fijémonos en los recuadros azules, son seis. Estos son los pasos que se ejecuta en el lado del servidor. Los recuadros blancos son como los "estímulos" para que la aplicación haga algo. Como podemos ver en el flujo, puede pasar desde los primeros recuadros "Restore View" y "Apply Request" hasta "Process Validations" si es que se aplica una validación, o puede ir directo a la última fase "Render Response" si es que no tiene nada que hacer. Esto último sucede cuando se llama a una página por primera vez y no se procesa nada, mas que mostrar el contenido de la página.
Para probar eso, vamos a crear una aplicación (que yo la llamé jsf-03-lifecycle) y tiene los siguientes
.xhtml
index.xhtml
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head > <title>Facelet Title</title> </h:head> <h:body > <h1>Formulario de prueba</h1> <h:form> <h:panelGrid columns="2"> <h:outputLabel value="Nombre" for="nombre"/> <h:inputText id="nombre" value="#{lifecycleBean.personaForm.nombre}" /> <h:outputLabel value="Sexo" /> <h:panelGroup layout="block"> <h:selectOneRadio value="#{lifecycleBean.personaForm.sexo}"> <f:selectItem itemLabel="Hombre" itemValue="H" /> <f:selectItem itemLabel="Mujer" itemValue="M" /> </h:selectOneRadio> </h:panelGroup> </h:panelGrid> <h:commandButton action="result" value="Enviar" /> </h:form> </h:body> </html>
result.xhtml
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>Facelet Title</title> </h:head> <h:body> <h2>Result</h2> <h:form> <h:panelGrid columns="2"> <h:outputText value="Nombre"/> <h:outputText value="#{lifecycleBean.personaForm.nombre}" /> <h:outputText value="Sexo"/> <h:outputText value="#{lifecycleBean.personaForm.sexo}" /> </h:panelGrid> <h:commandLink value="Regresar" action="index"/> </h:form> </h:body> </html>
Nuestro ManagedBean tendrá el siguiente código:
//Archivo LifecycleManagedBean.java package com.apuntesdejava.jsf.controladores; import com.apuntesdejava.jsf.bean.PersonaForm; import javax.enterprise.context.RequestScoped; import javax.inject.Named; @Named("lifecycleBean") @RequestScoped public class LifecycleManagedBean { private PersonaForm personaForm = new PersonaForm(); public LifecycleManagedBean() { } public PersonaForm getPersonaForm() { return personaForm; } public void setPersonaForm(PersonaForm personaForm) { this.personaForm = personaForm; } }
El bean que nos servirá de bean tiene el siguiente código:
//Archivo PersonaForm.java package com.apuntesdejava.jsf.bean; import java.util.Date; public class PersonaForm { private String nombre; private char sexo; private Date fechaRegistro; private String correoElectronico; public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public char getSexo() { return sexo; } public void setSexo(char sexo) { this.sexo = sexo; } public Date getFechaRegistro() { return fechaRegistro; } public void setFechaRegistro(Date fechaRegistro) { this.fechaRegistro = fechaRegistro; } public String getCorreoElectronico() { return correoElectronico; } public void setCorreoElectronico(String correoElectronico) { this.correoElectronico = correoElectronico; } }
Hasta aquí no hay nada extraordinario. Ahora debemos agregar un "oidor" que lo engancharemos al ciclo de vida para ver los efectos que sucede cuando ejecutamos la aplicación.
//Archivo MiPhaseListener.java package com.apuntesdejava.jsf.controladores; import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; import javax.faces.context.FacesContext; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.servlet.http.HttpServletRequest; public class MiPhaseListener implements PhaseListener { static final Logger LOGGER = Logger.getLogger(MiPhaseListener.class.getName()); @Override public void afterPhase(PhaseEvent event) { LOGGER.log(Level.INFO, "Después:{0}", event.getPhaseId()); } @Override public void beforePhase(PhaseEvent event) { LOGGER.log(Level.INFO, "Antes:{0}", event.getPhaseId()); } @Override public PhaseId getPhaseId() { return PhaseId.ANY_PHASE; } }
Y para engancharlo al ciclo de vida de la aplicación, debemos crear el archivo
faces-config.xml
en WEB-INF
. Si no existe el archivo, lo creamos desde la opción New File > JavaServer Faces > JSF Faces Configuration:
Una vez creado, registramos el listener en el .xml que acabamos de crear usando el siguiente código:
<?xml version='1.0' encoding='UTF-8'?> <faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"> <lifecycle> <phase-listener> com.apuntesdejava.jsf.controladores.MiPhaseListener</phase-listener> </lifecycle> </faces-config>
Ahora, ejecutaremos la aplicación, y veamos el log de cada petición que hagamos.
Veamos: La primera vez que ejecutamos:
Solo se presentan dos fases: RESTORE_VIEW y RENDER_RESPONSE. Es decir, la primera y la última fase.
Veamos qué pasa cuando colocamos valores y le damos clic en "Enviar":
Al parecer ya pasa por todas las fases del ciclo de vida. Veamos si ponemos una validación. Para ello agregamos las líneas resaltadas en el
index.html
como sigue:
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head > <title>Facelet Title</title> </h:head> <h:body > <h1>Formulario de prueba</h1> <h:form> <h:panelGrid columns="2"> <h:outputLabel value="Nombre" for="nombre"/> <h:inputText id="nombre" value="#{lifecycleBean.personaForm.nombre}" /> <h:outputLabel value="Correo electrónico" for="email"/> <h:inputText id="email" value="#{lifecycleBean.personaForm.correoElectronico}" > <f:validator validatorId="emailValidator"/> </h:inputText> <h:outputLabel value="Sexo" /> <h:panelGroup layout="block"> <h:selectOneRadio value="#{lifecycleBean.personaForm.sexo}"> <f:selectItem itemLabel="Hombre" itemValue="H" /> <f:selectItem itemLabel="Mujer" itemValue="M" /> </h:selectOneRadio> </h:panelGroup> </h:panelGrid> <h:commandButton action="result" value="Enviar" /> </h:form> </h:body> </html>
Y creamos la siguiente clase:
//EmailValidator.java package com.apuntesdejava.jsf.validation; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.FacesValidator; import javax.faces.validator.Validator; import javax.faces.validator.ValidatorException; @FacesValidator("emailValidator") public class EmailValidator implements Validator { private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\." + "[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*" + "(\\.[A-Za-z]{2,})$"; private final Pattern pattern; private Matcher matcher; public EmailValidator() { pattern = Pattern.compile(EMAIL_PATTERN); } @Override public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { matcher = pattern.matcher(value.toString()); if (!matcher.matches()) { FacesMessage msg = new FacesMessage("Falló la validación del correo electrónico.", "El formato de correo electrónico no es válido"); msg.setSeverity(FacesMessage.SEVERITY_ERROR); throw new ValidatorException(msg); } } }
Y al ejecutar el proyecto, ingresemos un valor no válido para el correo electrónico. Esto es lo que nos mostrará en el log del servidor:
(He limpiado el log antes de ejecutar el error. Esto es para poder más claramente el log que responde)
Como podemos ver, no muestra el paso 4 ni el paso 5. Es decir, no está actualizando el modelo, ni está dando la ejecución a la aplicación, ya que la validación no lo dejó.
De esta manera, nos podemos asegurar que cada fase se ejecuta de manera independiente, y no afecta con la lógica de nuestra aplicación. Si queremos validar una entrada de un campo, debemos asegurarnos que se haga en su capa respectiva (usando los validadores) y no cuando haya guardado los valores en el modelo, ya que sería más difícil el manejo de mensajes de error al usuario. Con esto en mente, veremos poco a poco como este ciclo de vida nos ayudará en las siguientes aplicaciones.
Esto es todo por ahora.
El código fuente lo pueden descargar desde aquí: https://java.net/projects/apuntes/downloads/download/web/Tutorial%20JSF%202.2/jsf-03-lifecycle.tar.gz
Bibliografía
El modelo del ciclo de vida lo tomé de: Java EE 7 Tutorial - 7.6 The Lifecycle of a JavaServer Faces Application
El ejemplo de validador de correo electrónico, lo tomé de aquí: Custom Email Validator in JSF.
Nos vemos en un siguiente post
Bendiciones para todos!
El ejemplo de validador de correo electrónico, lo tomé de aquí: Custom Email Validator in JSF.
Nos vemos en un siguiente post
Bendiciones para todos!
Comentarios
Publicar un comentario
Si quieres hacer una pregunta más específica, hazla en los foros que tenemos habilitados en Google Groups
Ah! solo se permiten comentarios de usuarios registrados. Si tienes OpenID, bienvenido! Puedes obtener su OpenID, aquí: http://openid.net/