miércoles, 8 de julio de 2015

Desarrollo de una aplicación web con Java EE (JSF + JPA) - Parte 3

En esta tercera parte terminaremos con las pruebas a la base de datos que empezamos en la parte anterior y crearemos el primer formulario de la aplicación.

En este serie vamos a desarrollar una aplicación web usando Java EE, integrando las siguientes tecnologías EclipseLink (JPA 2.1), PrimeFaces 5.0 JSF 2.0.

Para ello usaremos NetBeans IDE 8.0.2, y de base de datos MySQL 5.6.25, usando MySQL JDBC Driver 5.1.23 para conectar nuestra aplicación Java con MySQL, y MySQL Workbench 6.3 para gestionar y visualizar la base de datos.

Contenido
  1. Terminando las pruebas a entidades
  2. El primer controlador
  3. Programando una vista
  4. Conclusión - Link de Descarga del Proyecto

Terminando las pruebas a entidades

En la parte anterior hicimos una prueba de registro de información, y aprendimos cómo usar las entidades para persistir información de nuestra aplicación a la base de datos. Ahora, haremos una segunda prueba, pero ésta vez será de lectura, y veremos como obtener la información de la base de datos y usarla en nuestra aplicación.

Como vimos en la parte anterior, todo el acceso a datos se hace a través de una clase EntityManager, que se instancia a través de un EntityManagerFactory. Para recuperar información de la base de datos, usaremos una instancia de EntityManager que tiene métodos para crear objetos de tipo Query; la cual se utiliza para realizar consultas a la base de datos. Entonces, la secuencia de pasos que tenemos que implementar en el código es la siguiente:
  1. Obtener una instancia del EntityManagerFactory
  2. Obtener una instancia de EntityManager usando la instancia del EntityManagerFactory
  3. Obtener una instancia de Query usando el método .createQuery() de la instancia de EntityManager
  4. Instruir a la instancia de Query que ejecute la consulta, y procesar los datos devueltos por la misma
  5. Una vez terminada el procesamiento de datos, cerrar el objeto EntityManager usando su método .close()
  6. Cerrar el objecto EntityManagerFactory usando su método .close()
En NetBeans, hacemos click derecho en el nombre de nuestro proyecto y elegimos "New" > "Other" del menú contextual.

En la sección de "Categories" elegimos la carpeta "Java", y en la sección de "File Types", elegimos "Java Main Class", y damos click en "Next".

Proporcionamos un nombre al archivo, y utilizaremos el mismo paquete donde guardamos el archivo PruebaRegistro.java. (En mi caso, lo llamaré PruebaLectura que será guardada en el paquete com.nes.test). Damos click en "Finish".

Codificamos el archivo PruebaLectura usando los pasos descritos anteriormente.

PruebaLectura.java
package com.nes.test;

import com.nes.entidades.DetallePedido;
import com.nes.entidades.Pedido;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class PruebaLectura {
  
  public static void main(String[] args) {
    //Obtener una instancia de EntityManagerFactory
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("WebAppPU");
    //Obtener una instancia de EntityManager
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    
    //Obtener una instancia de Query
    Query query = entityManager.createQuery("SELECT p FROM Pedido p where p.id = 1");
    //Instruir a la instancia de Query que ejecute la consulta
    Pedido pedido = (Pedido) query.getSingleResult();
    //Procesar los datos devueltos
    System.out.println("Información de Pedido: ");
    System.out.println("ID: " + pedido.getId());
    System.out.println("Tienda: " + pedido.getTienda().getNombre());
    System.out.println("Usuario: " + pedido.getUsuario().getNombre());
    System.out.println("Detalle del pedido");
    for(DetallePedido detalle : pedido.getDetalle()){
      System.out.println("- Libro: " + detalle.getLibro().getNombre() +
        " Cantidad: " + detalle.getCantidad() +
        " Precio Unitario: " + detalle.getPrecioUnitario());
    }
    
    //Cerrar la instancia de EntityManager
    entityManager.clear();
    //Cerrar la instancia de EntityManagerFactory
    entityManagerFactory.close();
  }
  
}
Nótese que al momento de obtener la instancia de Query, es necesario pasarle un parámetro String al método .createQuery(). Este parámetro es la consulta a ejecutar en la base de datos, que debe estar escrita en JPQL. JPQL es un lenguaje de consulta definido por JPA. JQPL es similar a SQL, pero en vez de operar en tablas y columnas en la base de datos como lo hace SQL; JQPL opera en atributos y relaciones de nuestras entidades. Puedes leer más sobre el lenguaje JPQL en este link.

El método .getSingleResult() devuelve un objeto de tipo Object, pero como sabemos que nuestra Query retornará un pedido, es que le hacemos una conversión de tipo cast a tipo Pedido, y almacenamos su valor en una variable de trabajo. Finalmente, hacemos uso de los métodos getter y setter que codificamos en nuestras entidades para mostrar en consola la información traída de nuestra base de datos. Nótese lo fácil que es pasar de una entidad a otra: empezamos mostrando la información de la entidad Pedido, almacenada en la tabla "pedido" en la base de datos; y terminamos mostrando la información del detalle del pedido, que se encuentra almacenada en la tabla "detallepedido" en la base datos. Ésta es una de los beneficios de usar JPA; si no usáramos JPA tendríamos que haber realizado una consulta SQL a la base de datos para obtener los datos del pedido, y luego otra consulta SQL para obtener los datos del detalle del pedido. JPA hace esto por nosotros de manera automática.

Procedemos a ejecutar el archivo PruebaLectura.java. Para ello hacemos click derecho cualquier lugar del código del archivo y elegimos la opción "Run File" del menú contextual.

Se ejecuta nuestro código, y en la ventana de "Output" podemos ver el resultado de la ejecución: la consola muestra la información del pedido con ID igual a 1 y su detalle correspondiente.

En el ejemplo anterior, utilizamos JPA para buscar un pedido en particular. Ahora utilizaremos JPA para buscar una colección: mostraremos en consola todos los géneros de la base de datos. En el mismo archivo PruebaLectura.java, agregamos un poco más de código al final del archivo:

PruebaLectura.java
package com.nes.test;

import com.nes.entidades.DetallePedido;
import com.nes.entidades.Genero;
import com.nes.entidades.Pedido;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class PruebaLectura {
  
  public static void main(String[] args) {
    //Obtener una instancia de EntityManagerFactory
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("WebAppPU");
    //Obtener una instancia de EntityManager
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    
    //Obtener una instancia de Query
    Query query = entityManager.createQuery("SELECT p FROM Pedido p where p.id = 1");
    //Instruir a la instancia de Query que ejecute la consulta
    Pedido pedido = (Pedido) query.getSingleResult();
    //Procesar los datos devueltos
    System.out.println("Información de Pedido: ");
    System.out.println("ID: " + pedido.getId());
    System.out.println("Tienda: " + pedido.getTienda().getNombre());
    System.out.println("Usuario: " + pedido.getUsuario().getNombre());
    System.out.println("Detalle del pedido");
    for(DetallePedido detalle : pedido.getDetalle()){
      System.out.println("- Libro: " + detalle.getLibro().getNombre() +
        " Cantidad: " + detalle.getCantidad() +
        " Precio Unitario: " + detalle.getPrecioUnitario());
    }
    
    //Cerrar la instancia de EntityManager
    entityManager.clear();
    //Cerrar la instancia de EntityManagerFactory
    entityManagerFactory.close();
    
    //Obtener una instancia de EntityManagerFactory
    EntityManagerFactory entityManagerFactory1 = Persistence.createEntityManagerFactory("WebAppPU");
    //Obtener una instancia de EntityManager
    EntityManager entityManager1 = entityManagerFactory1.createEntityManager();
    
    //Obtener una instancia de Query
    Query query1 = entityManager1.createQuery("SELECT g FROM Genero g");
    //Instruir a la instancia de Query que ejecute la consulta
    List listaGeneros = (List) query1.getResultList();
    //Procesar los datos devueltos
    System.out.println();
    System.out.println("Lista de Generos");
    for(Genero g : listaGeneros) {
      System.out.println("ID: " + g.getId() + " Nombre: " + g.getNombre());
    }
    
    //Cerrar la instancia de EntityManager
    entityManager1.clear();
    //Cerrar la instancia de EntityManagerFactory
    entityManagerFactory1.close();
  }
  
}
Para procesar colecciones, hacemos uso del método .getResultList() de la clase Query. Y como sabemos que retornará información sobre genero, podemos hacer una conversión de tipo cast a List que almacenamos en una variable de trabajo. Finalmente, iteramos sobre la lista de Generos y mostramos el resultado en consola.

Volvemos a ejecutar el archivo PruebaLectura.java y ahora vemos que en la pestaña de "Output", además de la información del pedido mostrada anteriormente, también se muestra la información de los géneros registrados en la base de datos. (Me tomé la libertad de agregar más registros en la tabla Género de la base de datos para evidenciar este ejemplo)


Hasta este punto, hemos creado las entidades y hemos registrar y obtener información de nuestra base de datos; pero la idea es que los usuarios de la aplicación sean los que puedan registrar y consultar la información, y no estarla codificando nosotros mismos. En la siguiente parte, crearemos el primero formulario de la aplicación.

El primer controlador

Java Server Faces (JSF) utiliza el modelo de vista-controlador conocido como MVC. Según Wikipedia:
El modelo–vista–controlador (MVC) es un patrón de arquitectura de software que separa los datos y la lógica de negocio de una aplicación de la interfaz de usuario y el módulo encargado de gestionar los eventos y las comunicaciones. Para ello MVC propone la construcción de tres componentes distintos que son el modelo, la vista y el controlador.

El Modelo es la representación de la información con la cual el sistema opera; [..] el Controlador responde a eventos (usualmente acciones del usuario) e invoca peticiones al 'modelo' cuando se hace alguna solicitud sobre la información [..] y la Vista presenta el Modelo [..] en un formato adecuado para interactuar (usualmente la interfaz de usuario).


En nuestra aplicación, ya tenemos la parte del modelo: son nuestras entidades. En JSF, un controlador es implementado mediante una clase java con la anotación @ManagedBean. Y las vista es implementada mediante un archivo XHTML.

Vamos a crear un formulario para que los usuarios puedan registrar géneros en la base de datos. Para ello procederemos a crear el primer controlador. En la pestaña de "Projects", damos click derecho a nuestro proyecto y elegimos "New" > "Java Class" del menú contextual.

Proporcionamos un nombre para nuestro controlador, lo llamaremos "ControladorGenero" y será guardado en un nuevo paquete llamado "com.nes.controladores", y damos click en "Finish".



Codificamos el archivo ControladorGenero:

ControladorGenero.java
package com.nes.controladores;

import com.nes.entidades.Genero;
import javax.faces.bean.ManagedBean;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

@ManagedBean
public class ControladorGenero {
  private Genero genero = new Genero();
  
  public void registrarGenero() {
    //Obtener una instancia de EntityManagerFactory
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("WebAppPU");
    //Obtener una instancia de EntityManager
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    //Como vamos a persistir datos, abrimos una transacción
    entityManager.getTransaction().begin();
    //Persistimos la información
    entityManager.persist(genero);
    //Ejecutamos la transacción
    entityManager.getTransaction().commit();
    //Cerramos la instancia de EntityManager
    entityManager.close();
    //Cerramos la instancia de EntityManagerFactory
    entityManagerFactory.close();
  }
  
  public Genero getGenero() {
    return genero;
  }

  public void setGenero(Genero genero) {
    this.genero = genero;
  }
}
El controlador tiene un solo atributo de tipo Genero con sus respectivos métodos getter y setter. Y también tiene un método registrarGenero() que persiste la información del atributo de tipo Genero.

Programando una vista

Ahora procederemos a crear la primera vista que usará el controlador programado anteriormente. En la pestaña "Projects", expandimos el proyecto y le damos click derecho en "Web Pages", elegimos "New" > "Folder" del menú contextual.


Proporcionamos un nombre a la carpeta, la llamaremos "app", y damos click en "Finish".



Damos click derecho en la carpeta "app" y elegimos "New" > "Other" del menú contextual.


Proporcionamos un nombre, el cual llamaremos "registroGenero", y damos click en "Finish".


Editamos el contenido del archivo registroGenero.xhtml para que quede de la siguiente manera:

ControladorGenero.java
<?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:p="http://primefaces.org/ui">
  <h:head>
    <title>Registro de Género</title>
  </h:head>
  <h:body>
    <h:form>
      <h:outputLabel for="txtNombre" value="Nombre: " />
      <p:inputText id="txtNombre" value="#{controladorGenero.genero.nombre}" />
      <p:commandButton action="#{controladorGenero.registrarGenero}"
                       value="Guardar" />
    </h:form>
  </h:body>
</html>

Como podemos ver, la vista se compone de un formulario, el cual contiene una label con el valor de "Nombre: ", un input text (caja de texto), y un botón con el valor de "Guardar" para enviar el formulario. Nótese que para el input le asignamos el valor del atributo de tipo Genero del ControladorGenero, y que para el botón de envío de formulario le asignamos el método .registrarGenero() del ControladorGenero. Para hacer esta asignación, hacemos un binding con nuestro controlador, utilizando Expression Language. Para saber más sobre Expression Language puede revisar la documentación de Oracle.

Finalmente ejecutamos la aplicación, para eso damos click derecho en el archivo "registrarGenero.xhtml" de nuestra aplicación y elegimos "Run File" del menú contextual. La aplicación se despliega y se abre la ventana del browser mostrando el formulario:


Proporcionamos un nombre, y damos click en el botón de Guardar.


Revisamos la base de datos, y podemos observar que en la tabla Genero se ha insertado un nuevo registro.

Conclusión - Link de Descarga del Proyecto

Recapitulando, en esta parte terminamos con las pruebas de las entidades: realizando una pequeña prueba de lectura de información de la base de datos, demostrando que nuestra aplicación Java se conecta adecuadamente con la base de datos MySQL. También creamos el primer controlador y creamos la primera vista de la aplicación, la cual contiene un formulario que permite a los usuarios registrar géneros en la base de datos. Puedes descargar el código del proyecto de NetBeans hasta este punto haciendo click en este link.

La aplicación hasta ahora permite a los usuarios registrar géneros exitosamente, pero no se muestra algún mensaje notificando a los usuarios que el registro se hizo adecuadamente o no. En la siguiente parte, mejoraremos la interfaz de usuario y continuaremos con el desarrollo de la aplicación.

Referencias:

No hay comentarios:

Publicar un comentario