Ejemplo de uso con JSF 2.0, Primefaces e Hibernate

Ejemplo de uso con JSF 2.0, Primefaces e Hibernate


Índice de contenidos.


0. Repositorio de código

Puedes descargarte todos los ficheros que se han utilizado para este tutorial aquí.

Las librerías no se han añadido por su considerable peso, así que cuando te las bajes lo único que tienes que hacer es añadirlas al proyecto. Es aconsejable crearse una carpeta dentro del proyecto de nombre lib y desde la carpeta libraries en Netbeans añades el JAR, que previamente has ubicado en esa carpeta lib.


1. Enunciado del ejemplo

En este ejemplo vamos a suponer que somos unos cuantos amigos, a los que nos gustan los videojuegos y queremos mantener una lista actualizada de los juegos que nos compramos. Los datos que nos interesan son: una fotografía, el nombre, una descripción y el precio. En un principio queremos mostrar todos los juegos que tenemos y poder añadir nuevos juegos a medida que nos los vamos comprando y que de forma dinámica se añadan a la lista.


2. Tecnología que vamos a utilizar

Para este ejemplo, aunque sencillo, vamos a usar el patrón de diseño: modelo-vista-controlador.

  • Modelo: Para mantener los datos de los videojuegos, vamos a utilizar como gestor de bases de datos MySQL 5.1. Vamos a acceder a estos mediante Hibernate 3.2.5.
  • Vista: Para pintar los videojuegos en pantalla y permitir que se agreguen otros nuevos vamos a utilizar JSF 2.0 y Primefaces 2.1.
  • Controlador: En controlador tendremos nuestra lógica de negocio. El IDE que vamos a utilizar es Netbeans en su versión 6.8. Además como servidor utilizaremos GlassFish 3.

3. Empecemos con el Modelo

Lo decía Jack “el destripador” (vayamos por partes) y todos los profesores de algorítmica (divide y vencerás). Para afrontar un problema informático hay que dividirlo en partes más sencillas.


3.1 Instalación y configuración de Hibernate

Lo primero de todo es crear una base de datos para almacenar los datos de los videojuegos. Si no tenemos MySQL instalado podemos bajarlo de la página web oficial: http://www.mysql.com/downloads/. En la instalación es importante que nos quedemos con el puerto. En este ejemplo se ha dejado el puerto por defecto (3306). A continuación:

  • 1. Nos creamos una Base de datos de nombre videojuegos.
  • 2. Creamos una tabla de nombre juegos con los siguientes atributos: id, nombre, sinapsis, ruta (para guardar la ruta de la foto o carátula del juego) y precio.

Ahora vamos a configurar Hibernate para que pueda acceder a la base de datos que nos acabamos de crear. En Netbeans contamos con una interfaz visual bastante amigable aparte del XML.

Para una conexión directa con la base de datos serían necesarios los siguientes parámetros:

  • Driver para conexión con mysql.
  • La url compuesta por:
    • 1. Dirección: 127.0.0.1 ó podríamos poner también localhost.
    • 2. El puerto. Como no lo cambiamos sigue siendo el puerto por defecto 3306.
    • 3. El nombre de la base de datos.
  • El usuario: root.
  • La contraseña: admin.

Si nos fijamos en el archivo hibernate.cfg.xml, las propiedades quedarían de la siguiente forma.

En el XML tendría su correspondencia:

Nota: es muy recomendable que la contraseña no sea admin, sino algo más seguro.

Si nos fijamos en la línea 5 de nuestro XML tenemos el dialecto que es el correspondiente a MySQL. En la parte gráfica estaría dentro de Optional Properties en la subsección Configuration Properties.

Vamos a añadir una propiedad más a la configuración de Hibernate. Queremos que Hibernate linkee la session al hilo correspondiente de manera automática, por lo que añadimos lo siguiente:

En la interfaz gráfica esta propiedad puede verse dentro de Optional Properties en la subsección Miscellaneus Properties.

En este momento podemos conectar Hibernate con nuestra base de datos en MySQL. Ahora necesitamos una clase que tenga los mismos atributos que nuestra tabla juegos, para poder guardar los datos que escribimos o leemos de la base de datos. A estas clases se las conoce como POJO.


3.2 Creación del POJO

POJO o Plain Old Java Object, son clases que no dependen del framework, es decir, no heredan interfaces ni implementan clases del framework, que en este caso es Hibernate. Diríamos entonces que Hibernate es un framework no intrusivo. A la vez, Hibernate exige que las clases sean Bean, es decir, clases simples. Estas clases no tienen constructores con parámetros y se caracterizan por tener sus atributos marcados como privados, y una serie de métodos conocidos como getters y setters para leer o escribir dichos atributos. Vamos a llamar a nuestra nueva clase VideojuegoPojo que será de la siguiente forma.

Los setters deberían quedarnos como los siguientes.


3.3 Mapeo entre la base de datos y nuestra clase POJO

Ya tenemos configurada la conexión a la Base de Datos y tenemos nuestra clase Pojo para guardar información. Ahora solo nos queda hacer corresponder los atributos de la clase con los distintos campos de la tabla juegos. A esto se le llama mapping.

Para hacerlo, en nuestro package actual, pincharemos en New, y en Hibernate Mapping Wizard. Esto nos creará un archivo al que nosotros hemos llamado VideojuegoPojo.hbm.xml.

  • En la línea 4 estamos fijando el nombre de la clase (VideojuegoPojo) que queremos hacer corresponder con una tabla de la base de datos (juegos).
  • Si nos fijamos en las líneas 7-12, lo que estamos haciendo es generar la clave primaria de la tabla juegos, que se llama id, y es de tipo integer. Lo hacemos mediante el algoritmo Hilo que proporciona Hibernate. Este algoritmo genera un número único, que vale para claves primarias, a partir de una tabla auxiliar en la base de datos que se encarga de mantener el siguiente número a aplicar el algoritmo. Esta tabla en nuestro ejemplo es jid, que tendría un solo campo que es next, y que hemos inicializado en un principio a 1.

Nota: Podemos poner el campo id, que es primary key de la tabla juegos con AUTOINCREMENT. Si le damos esa propiedad cuando creamos la tabla juegos, no necesitaremos generar nosotros la clave.

Los demás atributos irían mapeados de la siguiente forma:

Por último tan solo nos queda hacer constancia en la configuración de hibernate de este mapeo. Lo podemos hacer incluyendo en el archivo hibernate.cfg.xml la siguiente línea.

En la parte gráfica se verían reflejados todos los mapeos en la pestaña de Mappings.


3.4 Creándonos nuestro DAO

DAO (Data Access Object) va a ser un componente mediante el cual accederemos a los datos. Creándonos el DAO, nuestra capa de negocio no necesitará conocer el destino final de la información que maneja. Aunque está considerado una buena práctica, si estamos en entornos donde el rendimiento es una prioridad no deberíamos utilizarlo.

Lo que queremos obtener para el ejemplo que estamos tratando es una lista de videojuegos con todos los juegos que tiene la base de datos, así como poder introducir uno nuevo. Estos métodos deberían ser parecidos a lo siguiente:

Si nos fijamos a partir de la línea 49 tenemos el modo estándar de hacer una transacción.

  • 1. Empezamos la transacción.
  • 2. Hacemos las operaciones en la base de datos.
  • 3. Hacemos el Commit.
  • 4. Si algo ha ido mal lo notificamos en el Logger y hacemos un Rollback para que la base de datos vuelva al mismo estado previo a las operaciones.

En la línea 48 vemos que está implicada la clase ConfHibernate. Esto no es más que el Session Factory. Está detallado a continuación.


NOTA: Tenemos solo una session, por eso esta clase no tiene constructor. Cuando queramos usar la session lo haremos mediante la llamada getCurrentSession(); Al finalizar deberemos cerrar la session, en este ejemplo en el destructor del DAO.

Ya solo nos quedaría la parte necesaria para introducir un juego nuevo en la base de datos. Completaríamos nuestro DAO con el siguiente método.


4. Creando la Vista y el Controlador

La vista va a estar dividida en dos partes. En una primera parte vamos a tener los videojuegos y debajo vamos a dar la opción de introducir uno nuevo. Para mostrar los videojuegos nos vamos a servir de Primefaces, ya que sus componentes nos van a resultar muy útiles. Para poder utilizarlos primero vamos a tener que configurar el archivo web.xml, para añadir los filtros necesarios para subir ficheros, en donde podremos indicar filtros para los tamaños de los ficheros, y el Servlet de Primefaces. Web.xml nos quedaría de la siguiente forma.


Ahora ya podemos usar Primefaces en nuestro index.xhtml. Para la primera parte vamos a usar un componete de Primefaces llamado dataTable. Este componente se rellena con una lista de objetos, que van a ser nuestros videojuegos, de la siguiente forma.

NOTA: Primefaces es un Api con más de 90 componentes para JSF que podeis descargaros de http://www.primefaces.org/downloads.html.

Podemos observar en la línea 16 como la tabla se va a pintar a partir de un atributo de la clase TableVideojuegoPojo, que se llama listaVideojuegos. La clase TableVideojuegoPojo sería pues nuestro controlador, encargado de pedir al DAO los datos, y si fuera necesario modificarlos o hacer cualquier tipo de tratamiento antes de mostrarlos en la vista. En la línea 22 si nos fijamos estamos construyendo la dirección de la foto a pintar teniendo en cuenta la carpeta que contiene DAO y la ruta de la foto. Esto se detalla más adelante. Nuestro controlador es muy simple en este caso.

Quizás lo más importante sea la línea 11 @ManagedBean, con lo que estamos indicando que la vista va a tener acceso a sus atributos, precisamente mediante los getters y setters.

Para la segunda parte simplemente vamos a dar la opción al usuario de rellenar los datos de un nuevo videojuego, subir una foto y darlo de alta en la base de datos. Después debería actualizarse la tabla para mostrarlo. Nos quedaría algo parecido a lo siguiente.

Como vemos, los datos que introduce el usuario los vamos a ir guardando en la clase nuevoJuegoBean, que también estaría actuando de controlador. Le estaríamos a su vez encargando la subida de la foto como se puede ver en la línea 49, así como grabar el juego (nuevoJuegoBean.grabarJuego) y actualizar la tabla (update=”table”), acciones ambas contempladas en la línea 53. Vamos ahora a ver cómo podemos grabar todos los atributos de un juego en una misma instancia de nuevoJuegoBean, gestionar la foto y grabarlo todo en la base de datos.

Un punto importante es la línea 15. Con @ViewScoped lo que estamos indicando es que todos los parámetros que introdujo el usuario en el form anterior se van a guardar en la misma instancia de NuevoJuegoBean, y se va a gestionar la foto y se va a subir con los atributos que se han introducido. Si no lo pusiéramos se nos crearían varias instancias de NuevoJuegoBean y cuando fuéramos a grabar el juego no podríamos ver el Nombre, la sinapsis, la descripción y la ruta de la foto. Igual que vemos en la foto algunos setters, estarían los getters.

En cuanto a grabarJuego, simplemente tendríamos que pasarle al DAO los datos indicados por el usuario. De esta forma estamos ganando abstracción. A este nivel no sabemos donde se van a guardar esos datos, el DAO se encarga de ello. En esta línea va también el método que hay a continuación, el accionFileUpload. Este método simplemente se encarga de quedarse con la ruta de la foto, que es lo que se guarda en la base de datos, y le encarga al DAO la administración de la misma. Así desde este nivel no conocemos la carpeta o directorio donde se va a guardar la misma, ganando en abstracción. Vamos ahora a completar nuestro DAO que sí tendrá esas direcciones tanto virtuales como físicas donde se guardan las imágenes y a su método gestionarFotoSubida.

La carpeta virtual sería /Imagenes/ y la carpeta física para este ejemplo sería C:\\Users\\Alberto\\Documents\\NetBeansProjects\\Gamer\\build\\web\\Imagenes\\ y es donde guardaremos físicamente la foto que manda el usuario de la siguiente forma.

Con esto tendríamos completo el DAO.


5. Conclusiones

Después de haber probado la librería he podido observar las siguientes ventajas:

  • Primefaces cuenta con un buen número de componentes (más de 90) que resultan estéticamente muy agradables.
  • Primefaces es compatible con JSF 1.2 en su versión 1, y compatible con JSF 2.0 en su versión 2.
  • Soporta Ajax sin que el desarrollador tenga que ver o hacer casi nada. Ya hemos visto que con indicar que el componente dataTable sea dinámico, y hacer un update de ese componente desde cualquier otro, tendríamos solucionado la actualización.
  • Se trata de una librería en crecimiento con una comunidad muy activa. Cuentan con un foro de soporte bastante acitvo en donde resuelven dudas y reciben feedback de los usuarios para mejorar la librería y corregir bugs.

Primefaces me ha parecido una opción a tener muy en cuenta a la hora de trabajar con JSF.