El framework de presentación JSF
Visión general
El uso de servlets y JSP en un proyecto a gran escala, no resulta sencillo. Es preferible utilizar un framework que ofrezca un marco de arquitectura bien definido y un conjunto de componentes que limiten el código redundante e incómodo. El objetivo de este capítulo es descubrir los conceptos básicos del framework MVC JSF 3.0 (Jakarta Server Faces), que es un framework orientado a componentes.
Un framework orientado a componentes es un framework que manipula los componentes visuales y de negocio, limitando al mismo tiempo el uso directo de las tecnologías web tanto como sea posible. En este sentido, este tipo de framework se parece al desarrollo de una aplicación cliente/servidor. Por lo tanto, los desarrolladores sin experiencia en el desarrollo web pueden obtener resultados rápidamente.
En oposición a este tipo de framework, existen otros orientados a la acción. Este tipo de framework maneja las peticiones y respuestas HTTP. Un framework de este tipo está mucho más cerca del protocolo HTTP y las tecnologías satelitales. Se basa claramente en las tecnologías presentadas en los capítulos anteriores. Por ejemplo, es el caso de Struts 2.
Sin embargo, ambos tipos de frameworks respetan el patrón MVC (modelo-vista-controlador). Por lo tanto, proponen una arquitectura que permite la separación entre el modelo, la vista y el controlador.
Presentación de JSF
1. Aspectos generales
JSF es una tecnología de Jakarta que actualmente se encuentra en su versión 3.0. La documentación oficial está disponible en: https://jakarta.ee/specifications/faces/3.0/jakarta-faces-3.0.pdf
En este capítulo se utiliza la implementación de referencia, denominada Mojarra 3.0. El sitio web de referencia para esta implementación se puede encontrar en la dirección https://eclipse-ee4j.github.io/mojarra/
JSF consta de los siguientes elementos:
-
Una API para representar componentes y administrar su estado. Estos componentes se denominan managedBeans (también llamados backingBeans).
-
Una API para gestionar eventos, validaciones del lado del servidor, conversión de datos, navegación e internacionalización.
-
Librerías de tags o etiquetas, como las disponibles para JSP (etiquetas JSTL), que permiten proporcionar una representación adecuada de managedBeans. Las páginas JSF se llaman facelets.
2. Principios de funcionamiento
El funcionamiento se basa en un conjunto de pasos (ciclo de vida) desde la llegada de la petición HTTP hasta la representación de la respuesta. El siguiente diagrama muestra cómo funciona esto.
El ciclo de vida se compone de seis etapas, entre las cuales se intercalan fases de gestión de eventos (Process Events) no cubiertas en este libro:
-
Restore View: esta es la primera etapa que se realiza cuando se ejecuta una petición a un recurso JSF. Esta etapa se utiliza para constituir en memoria un árbol de componentes...
Configuración general
1. El archivo faces-config.xml
El archivo faces-config.xml, ubicado en el directorio webapp/WEB-INF, es un archivo de configuración opcional en el uso de JSF. Debe tener el siguiente contenido mínimo, con la etiqueta raíz <faces-config>:
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_3_0.xsd"
version="3.0">
</faces-config>
A título informativo, este archivo solo se modifica ligeramente en el contexto de este capítulo porque los ejemplos implementados son relativamente simples y utilizan las anotaciones o configuraciones predeterminadas.
2. El archivo beans.xml
El archivo beans.xml, ubicado en el directorio webapp/WEB-INF, es un archivo de configuración necesaria para usar la inyección de dependencias a través de la API Weld. Debe tener el siguiente contenido mínimo con la etiqueta raíz <beans>:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee" ...
El ejemplo
El ejemplo que se va a utilizar en el resto del capítulo implementará un formulario para introducir un nuevo deporte. Para hacer esto, es necesario utilizar las clases Java del paquete fr.ediciones_eni.jakartaee.modelos de los proyectos anteriores. Como recordatorio, a continuación se muestra el contenido de este paquete:
Para añadir un deporte, es necesario introducir un nombre, el número de jugadores y la selección de las superficies en las que se puede jugar. Por lo tanto, se utilizan las clases Deporte y Superficie. Ambas clases siguen las convenciones de un JavaBean.
ManagedBeans
1. Presentación
Los managedBeans se corresponden con los controladores de su proyecto. En este sentido, reaccionan a las acciones del usuario y proporcionan la información que se ha de mostrar.
Un managedBean es simplemente una clase Java anotada con @Named o declarada como tal en el archivo faces-config.xml a través de la etiqueta <managed-bean>. La anotación @Named tiene un parámetro value, que permite dar a esta clase un nombre lógico. Si este atributo se deja en blanco, el nombre predeterminado es el nombre de la clase en minúsculas (independientemente del nombre del paquete). Este nombre es importante para usar el managedBean en una facelet.
Un BusinessdBean a menudo se asocia con una o más facelets (correspondientes a la vista). Tiene propiedades (variables miembro privadas con getters/setters públicos) que se corresponden con la información mostrada en la facelet. También tiene métodos que se llaman en función de las acciones realizadas por el usuario. Necesariamente, tiene un constructor sin parámetros.
Un managedBean también se anota con una anotación que determina su ámbito (@RequestScoped, @ViewScoped, @SessionScoped, @ApplicationScoped). Si el estado del managedBean no se debe guardar después de devolver la respuesta, se debe utilizar la anotación @NoneScoped. En ausencia de dicha anotación, el valor predeterminado...
Facelets
1. Librerías
Desde JSF 2.0, Facelets es la tecnología de visualización estándar. Se basa en un lenguaje de marcado XML. Las librerías disponibles incluyen:
Librería |
Uri |
Prefijo |
La librería html |
h |
|
La librería principal |
f |
|
La librería facelets |
ui |
Una descripción detallada de estas librerías está disponible en: https://javaserverfaces.java.net/nonav/docs/2.0/pdldocs/facelets
También es posible hacer referencia a librerías JSTL. Para obtener más información sobre el uso de etiquetas JSTL, consulte la sección Etiquetas JSTL del capítulo sobre JSP.
La estructura básica de una facelet
La estructura básica de una facelet es la siguiente:
<!DOCTYPE html>
<html
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<!—su código aquí-->
</html>
La etiqueta raíz <html> se utiliza para declarar las librerías que se pueden utilizar. Las tres primeras declaraciones se corresponden con las librerías de la tecnología Facelets, y la cuarta, con la JSTL core.
La extensión del archivo es .xhtml. No es una JSP. Las etiquetas <jsp:xxx> no se pueden utilizar y el código Java está prohibido. Solo se puede utilizar EL. Por lo tanto, una facelet es mucho más homogénea (en su contenido), que una JSP.
La librería html
La librería html proporciona las etiquetas que van a utilizar los diferentes componentes gráficos que se mostrarán. El nombre de las etiquetas es auto-explicativo. Puede consultar la documentación oficial para obtener la lista completa. Sin embargo, aquí hay algunos ejemplos:
-
La etiqueta <h:form>: esta etiqueta se utiliza para configurar una etiqueta html <form>.
-
La etiqueta <h:commandButton>: esta etiqueta se utiliza para configurar una etiqueta html <input> de tipo submit .
-
La etiqueta <h:inputText>: esta etiqueta se utiliza para configurar...
Conversiones
El mecanismo de conversión es esencial para cerrar la brecha entre la representación textual en el lado del cliente y la representación de objetos en el lado del servidor. La conversión se basa en la implementación de la interfaz jakarta.faces.convert.Converter. Existen implementaciones estándar que permiten las conversiones más comunes de una cadena de caracteres a un tipo determinado:
-
BigDecimalConverter
-
BigIntergerConverter
-
BooleanConverter
-
ByteConverter
-
CharacterConverter
-
DateTimeConverter
-
DoubleConverter
-
FloatConverter
-
IntegerConverter
-
LongConverter
-
NumberConverter
-
ShortConverter
Por supuesto, no hay un convertidor para las superficies, por lo que tenemos que crearlo. Para hacer esto, simplemente cree una clase que implemente la interfaz Converter<T>. La clase SuperficieConverter del paquete fr.ediciones_eni. jakartaee.converters implementa esta interfaz. El código para esta clase es el siguiente:
@FacesConverter(value="SuperficieConverter")
public class SuperficieConverter implements Converter<superficie>
{
@Override
public Superficie getAsObject(FacesContext context, UIComponent
component, String value)
{
return new Superficie(value, Surface.HORMIGON);
}
@Override
public String getAsString(FacesContext context, UIComponent
component, Superficie value)
{
return value!=null?value.getCode():null;
}
}
La interfaz necesita dos métodos para ser implementada:
-
El método Object...
Validaciones
La principal debilidad del programa que hemos escrito hasta el momento es que no hay control de la entrada de datos. De hecho, el usuario puede ingresar lo que quiera en el nombre y en el número de jugadores. De esta manera, la página de confirmación podría ser parecida a lo siguiente:
La aplicación confirma la creación de un deporte sin nombre, sin superficie y con un número de jugadores igual a -5. Es importante realizar comprobaciones de entrada y alertar al usuario en caso de problemas. Esto se corresponde con el mecanismo de validación.
La validación se puede establecer en diferentes lugares:
-
A nivel de la facelet utilizando validadores predefinidos.
-
A nivel de una clase Java correspondiente a un validador específico.
-
A nivel de una clase del modelo con la especificación Bean Validation.
Estas son las reglas que se deben implementar:
-
El nombre es obligatorio.
-
Se debe seleccionar al menos un terreno de juego.
-
El número de jugadores debe estar entre 1 y 10.
1. Validación en la facelet
La validación en la facelet implica el uso de validadores predefinidos. A continuación, se muestra la lista de estos validadores:
-
<f:validateDoubleRange>: este validador se utiliza para evaluar el valor introducido en el componente gráfico asociado. Este valor debe ser un doble válido, comprendido entre los límites definidos por los atributos minimo y maximo. Al menos se debe indicar uno de estos atributos.
-
<f:validateLength>: este validador se utiliza para evaluar el tamaño del valor introducido en el componente gráfico asociado. El tamaño debe estar comprendido entre los límites minimo y maximo. Al menos se debe indicar uno de estos atributos. El valor de estos atributos debe ser un doble positivo.
-
<f:validateLongRange>: este validador se utiliza para evaluar el valor introducido en el componente gráfico asociado. Este valor debe ser un long válido entre los límites definidos por los atributos minimo y maximo. Al menos se debe indicar uno de estos atributos.
-
<f:validateRegex>: este validador verifica que la entrada del componente gráfico asociado respeta la expresión regular definida por el atributo pattern. La clase java.util.regex.Pattern gestiona esta expresión regular. Para obtener más información acerca de las expresiones...
Internacionalización
La internacionalización permite adaptar la aplicación a los idiomas de los usuarios. El funcionamiento básico es el mismo que el presentado en el capítulo relativo a las JSP, en la sección Etiquetas JSTL - La librería de internacionalización y formateo (fmt) - Los aspectos principales.
El resto de la sección explicará la internacionalización basada en el atributo de petición HTTP Accept-Language.
1. Crear el archivo .properties
El primer paso es crear el archivo .properties para todos los idiomas admitidos por la aplicación. Como parte del ejemplo, se crean dos archivos:
-
Mensajes.properties
-
Mensajes_en.properties
El primer archivo se corresponde con los recursos predeterminados. Los mensajes están escritos en castellano. El segundo se corresponde con recursos escritos en inglés. Estos archivos contienen información con el formato clave=valor.
Estos dos archivos se colocan en el directorio main/resources del proyecto para que se desplieguen en el directorio /WEB-INF/classes.
El contenido del archivo Mensajes.properties es el siguiente:
template.tituto.defaut=Título por defecto
header.titulo=Cabecera JSF
footer.contenido=Ediciones ENI
deporte.label.nombre=Nombre
deporte.label.superficies=Supercies
deporte.label.numeroJugadores=Número de jugadores
deporte.boton.validar=Validar
deporte.error.superficies=Por favor, seleccione al menos un terreno
de juego
zona.error.obligatorio=El valor es obligatorio
El contenido del archivo Mensajes_en.properties es el siguiente:
template.titulo.defaut=Default title
header.titulo =JSF header
footer.contenido=Editions ENI
deporte.label.nombre=Name
deporte.label.superficies=Fields
deporte.label.numeroJugadores=Number of players
deporte.boton.validar=Submit
deporte.error.superficies=Please, select at least one field
zona.error.obligatorio=The value is mandatory
2. La declaración en el archivo faces-config.xml
La creación del archivo .properties requiere su declaración en el archivo faces-config.xml para facilitar su uso en las facelets. A continuación, se muestra la configuración que se debe realizar:
<application>
<resource-bundle> ...
Conclusión
Este capítulo ha presentado las líneas principales para ponerse manos a la obra tranquilamente con JSF.
El uso de un framework como JSF es un activo para proyectos de cierto tamaño porque impone una arquitectura con una clara separación de responsabilidades entre los diferentes componentes.
Para ir más allá, no dude en consultar la documentación oficial de este framework. No se han abordado todas sus posibilidades, ni mucho menos. Temas como la seguridad o el acoplamiento con JavaScript son elementos importantes.