¡Bienvenidos a todos! Esta publicación formará parte de una serie de 10 publicaciones que estaré desarrollando para aprender a crear una aplicación web en Java, bajo la plataforma JEE usando los frameworks de JPA y JSF. Este será un curso en forma de guía para todas aquellas personas que estén empezando en el mundo de la programación web.
En este curso aprenderemos a desarrollar aplicaciones web en N-CAPAS utilizando los patrones de diseño JEE, el estilo arquitectónico MVC y las funcionalidades provistas por los framework JSF (Java Server Faces) a nivel de vista-controlador y por JPA (Java Persistence API) a nivel de persistencia.
Este curso estará dividido en dos partes, En la primera parte, aprenderemos a configurar y utilizar el framework JPA mediante el desarrollo de aplicaciones Stand.Alone. En la segunda parte, aprenderemos a utilizar el framework JSF para desarrollar aplicaciones web. Por último, integraremos las funcionalidades de ambos frameworks en una aplicación final.
En este curso aprenderemos a desarrollar aplicaciones web en N-CAPAS utilizando los patrones de diseño JEE, el estilo arquitectónico MVC y las funcionalidades provistas por los framework JSF (Java Server Faces) a nivel de vista-controlador y por JPA (Java Persistence API) a nivel de persistencia.
Este curso estará dividido en dos partes, En la primera parte, aprenderemos a configurar y utilizar el framework JPA mediante el desarrollo de aplicaciones Stand.Alone. En la segunda parte, aprenderemos a utilizar el framework JSF para desarrollar aplicaciones web. Por último, integraremos las funcionalidades de ambos frameworks en una aplicación final.
APLICACIÓN STAND-ALONE
Continuando con el post anterior donde vimos una primera aproximación al uso de JPA implementando un proyecto Stand-Alone que permita realizar un CRUD a una tabla determinada. Hoy, aprenderemos a crear una clase EntityListener para monitorear el ciclo de vida de una entidad.
OBJETIVOS
. Definimos un EntityListener para comprender el Ciclo de Vida de una Entidad.
PASOS
1. Ejecutar el proyecto del post anterior
Continuando con el post anterior donde vimos una primera aproximación al uso de JPA implementando un proyecto Stand-Alone que permita realizar un CRUD a una tabla determinada. Hoy, aprenderemos a crear una clase EntityListener para monitorear el ciclo de vida de una entidad.
. Definimos un EntityListener para comprender el Ciclo de Vida de una Entidad.
. Definimos más anotaciones (@Basic, @Column, @Transient).
. Definimos estrategias de generación de llave primaria usando (Identity, table, AUTO).
PASOS
1. Ejecutar el proyecto del post anterior
Paso 1: Importar el proyecto del post anterior
Vamos a crear una copia del proyecto de la sesión anterior y le cambiaremos el nombre a "Aplicacion_JPA_02".
persistence.xml...
<persistence-unit name="Aplicacion_JPA_02">"
EmpleadoJPA
"emf =Persistence.createEntityManagerFactory("Aplicacion_JPA_02");"
Ver como importar un proyecto JPA aquí.Vamos a crear una copia del proyecto de la sesión anterior y le cambiaremos el nombre a "Aplicacion_JPA_02".
Después de importar nuestro proyecto, ejecutamos el archivo "script1" que se encuentra dentro de la carpeta "bd". Asimismo, es opcional cambiar el nombre a la unidad de persistencia en el archivo "persistence.xml" y también la referencia a ella en el método "setup" de la clase "EmpleadoJPA", las cuales tienen el nombre del proyecto anterior "Aplicacion_JPA_01". Ustedes pueden ponerle el nombre que deseen a su unidad de persistencia, yo le pondré "Aplicacion_JPA_02" para que vaya acorde con el nombre del proyecto.
persistence.xml...
<persistence-unit name="Aplicacion_JPA_02">"
EmpleadoJPA
"emf =Persistence.createEntityManagerFactory("Aplicacion_JPA_02");"
El proyecto debe tener la siguiente estructura:
Hasta aquí es lo que hemos visto en el post anterior.
2. Comprendiendo el Ciclo de Vida de una Entidad
Paso 1: Creación del Entity Listener
Dentro del paquete "edu.aprender.persistence.entity.listener" creamos la clase “EmpleadoListener.java” con las siguientes propiedades:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | package edu.aprender.persistence.entity.listener; import javax.persistence.PostLoad; import javax.persistence.PostPersist; import javax.persistence.PostRemove; import javax.persistence.PostUpdate; import javax.persistence.PrePersist; import javax.persistence.PreRemove; import javax.persistence.PreUpdate; import org.apache.log4j.Logger; import edu.aprender.persistence.entity.Empleado; import edu.aprender.test.EmpleadoTest; public class EmpleadoListener { static Logger logger = Logger.getLogger(EmpleadoTest. class .getName()); @PrePersist public void listener_before_insert(Empleado empleado){ logger.debug( "@PrePersist: " +empleado.toString()); } @PreUpdate public void listener_before_update(Empleado empleado){ logger.debug( "@PreUpdate: " +empleado.toString()); } @PreRemove public void listener_before_delete(Empleado empleado){ logger.debug( "@PreRemove: " +empleado.toString()); } @PostLoad public void listener_after_query(Empleado empleado){ logger.debug( "@PostLoad: " +empleado.toString()); } @PostPersist public void listener_after_insert(Empleado empleado){ logger.debug( "@PostPersist: " +empleado.toString()); } @PostUpdate public void listener_after_update(Empleado empleado){ logger.debug( "@PostUpdate: " +empleado.toString()); } @PostRemove public void listener_after_delete(Empleado empleado){ logger.debug( "@PostRemove: " +empleado.toString()); } } |
Paso 2: Uso del EntityListener
Utilizando anotaciones en la entidad “Empleado.java”.
a) Para asociar un Entity Listener a una Entidad se debe utilizar la anotación @EntityListeners la cual indica la clase que implementa los métodos “callbacks” gestionados por anotaciones como @PrePersist.
En la clase "Empleado.java" añadir la línea de código resaltada:
1 2 3 4 5 | @EntityListeners (EmpleadoListener. class ) @Entity @Table (name= "tb_empleado" ) public class Empleado { } |
Paso 3: Probar aplicación
3. ORM y Anotaciones
Paso 1: Anotacions @Basic, @Column, @Transient
Ejemplo:
Vamos a ejecutar este "script2" donde se ha modificado los nombre de las columnas:
Añadir anotaciones en la entidad “Empleado”, según lo resaltado y definir sus métodos de acceso getters and setters.
Por ejemplo:
a) Añadir a la entidad "Empleado" el atributo “nombreCompleto”
b) Generar "getter/setter" y redefinir el método "toString()"
c) Probamos la aplicación
4. Manejo de Llave Primaria
Paso 1: @GenerateValue
Vamos a definir una estrategia de generación de llave Primaria
Estrategia 1 usando "IDENTITY"
Añadir en la entidad "Empleado" lo resaltado:
En la clase "EmpleadoTest" comentar la línea resaltada y volver a Probar:
Revisar en el log el código autogenerado
Estrategia 2 usando "TABLE"
Crear una tabla adicional en la base de datos de ejemplo, según el "script3":
Nos dirigimos a la clase "EmpleadoTest", clic derecho, /Run As/Java Application para ejecutar la aplicación.
Paso 1: Anotacions @Basic, @Column, @Transient
La anotación @Basic (que es opcional) se utiliza para indicar de forma explícita que dicho atributo debe ser almacenado en la base de datos. Por defecto, todas los atributos de una Entidad tienen asignada dicha anotación.
La anotación @Column (que es opcional) se utiliza para indicar las características físicas de la columna en la tabla de base de datos. Es necesario su uso por ejemplo cuando el nombre de la columna de la tabla de base de datos es distinto al del atributo definido en la Entidad.
Ejemplo:
Vamos a ejecutar este "script2" donde se ha modificado los nombre de las columnas:
1 2 3 4 5 6 7 8 9 10 11 | USE mysqljpa; DROP TABLE IF EXISTS tb_empleado; CREATE TABLE tb_empleado ( COD_EMP int ( 10 ) unsigned NOT NULL AUTO_INCREMENT, NOM_EMP varchar( 45 ) NOT NULL, APE_EMP varchar( 45 ) NOT NULL, EDA_EMP int ( 10 ) unsigned NOT NULL, ARE_EMP varchar( 45 ) NOT NULL, PRIMARY KEY (COD_EMP) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; |
Añadir anotaciones en la entidad “Empleado”, según lo resaltado y definir sus métodos de acceso getters and setters.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @EntityListeners (EmpleadoListener. class ) @Entity @Table (name= "tb_empleado" ) public class Empleado { @Id @Column (name= "COD_EMP" ,unique= true ,nullable= false ) private int id; @Basic @Column (name= "NOM_EMP" ,length= 45 , columnDefinition= "unsigned NOT NULL" , insertable= true , updatable= true ) private String nombre; @Basic @Column (name= "APE_EMP" , length= 45 , nullable= false , insertable= true , updatable= true ) private String apellido; @Basic @Column (name= "EDA_EMP" ,nullable= false , insertable= true , updatable= true ) private int edad; @Basic @Column (name= "ARE_EMP" ,length= 45 , nullable= false , insertable= true , updatable= true ) private String area; } |
La anotación @Transient (que es opcional) se utiliza para indicar aquellos atributos que no forman parte de ninguna tabla relacional. Atributos cuyo valor se genera en tiempo de ejecución para realizar alguna funcionalidad, pero cuyo valor no necesita ser persistente.
Entonces la entidad "Empleado" quedaría de la siguiente manera:
Por ejemplo:
a) Añadir a la entidad "Empleado" el atributo “nombreCompleto”
b) Generar "getter/setter" y redefinir el método "toString()"
c) Probamos la aplicación
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Transient private String nombreCompleto; public String getNombreCompleto() { return getNombre().concat( " " ).concat(getApellido()); } public void setNombreCompleto(String nombreCompleto) { this .nombreCompleto = nombreCompleto; } @Override public String toString() { return "Empleado [id=" + id + ", apellido=" + apellido + ", nombre=" + nombre + ", edad=" + edad + ", area=" + area + ", nombreCompleto=" + getNombreCompleto() + "]" ; } |
4. Manejo de Llave Primaria
Paso 1: @GenerateValue
Vamos a definir una estrategia de generación de llave Primaria
Estrategia 1 usando "IDENTITY"
Añadir en la entidad "Empleado" lo resaltado:
1 2 3 4 | @Id @Column (name= "COD_EMP" ,unique= true ,nullable= false ) @GeneratedValue (strategy= GenerationType.IDENTITY) private int id; |
En la clase "EmpleadoTest" comentar la línea resaltada y volver a Probar:
1 2 3 4 5 6 7 8 9 10 11 | public static void main(String[] args) { EmpleadoJPA empleadoJPA = new EmpleadoJPA(); empleadoJPA.setup(); // Entidad con datos estáticos Empleado entidadEmpleado = new Empleado(); //entidadEmpleado.setId(1); entidadEmpleado.setNombre( "Antonio" ); entidadEmpleado.setApellido( "Perez" ); entidadEmpleado.setEdad( 30 ); entidadEmpleado.setArea( "Sistemas" ); |
Revisar en el log el código autogenerado
Estrategia 2 usando "TABLE"
Crear una tabla adicional en la base de datos de ejemplo, según el "script3":
1 2 3 4 5 6 7 8 9 10 | use mysqljpa; DROP TABLE IF EXISTS tb_secuencia; CREATE TABLE tb_secuencia( descripcion varchar( 10 ) NOT NULL, valor int ( 10 ) NOT NULL, PRIMARY KEY (descripcion) ); insert into tb_secuencia values( 'empleado' , 0 ); |
En la entidad "Empleado" añadir el código resaltado:
1 2 3 4 5 | @Id @Column (name= "COD_EMP" ,unique= true ,nullable= false ) @GeneratedValue (strategy= GenerationType.TABLE, generator= "generador" ) @TableGenerator (name= "generador" , table= "tb_secuencia" , pkColumnName= "descripcion" ,valueColumnName= "valor" , pkColumnValue= "empleado" , allocationSize= 1 ) private int id; |
Probar aplicación y revisar en el log el código autogenerado
Estrategia 3 usando "AUTO"
En la entidad "Empleado" actualizar según el código resaltado:
En el caso de Mysql, la estrategia "AUTO" selecciona como mejor opción obtener el código de la tabla “sequence”, en caso de tener una tabla con nombre distinto pero con las mismas características, hay que indicar un "TableGenerator", tal cual se ve en el ejemplo.
Probar la aplicación y revisar el log el código autogenerado.
La clase entidad Empleado.java
Pasos para Importar y ejecutar el proyecto
1. Descargar el proyecto finalizado desde aquí
Estrategia 3 usando "AUTO"
En la entidad "Empleado" actualizar según el código resaltado:
1 2 3 4 5 | @Id @Column (name= "COD_EMP" ,unique= true ,nullable= false ) @GeneratedValue (strategy= GenerationType.AUTO, generator= "generador" ) @TableGenerator (name= "generador" , table= "tb_secuencia" , pkColumnName= "descripcion" ,valueColumnName= "valor" , pkColumnValue= "empleado" , allocationSize= 1 ) private int id; |
En el caso de Mysql, la estrategia "AUTO" selecciona como mejor opción obtener el código de la tabla “sequence”, en caso de tener una tabla con nombre distinto pero con las mismas características, hay que indicar un "TableGenerator", tal cual se ve en el ejemplo.
Probar la aplicación y revisar el log el código autogenerado.
La clase entidad Empleado.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | package edu.aprender.persistence.entity; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EntityListeners; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.TableGenerator; import javax.persistence.Transient; import edu.cibertec.persistence.entity.listener.EmpleadoListener; @EntityListeners (EmpleadoListener. class ) // Es para mandar las anotaciones del previa a una clase listener @Entity // Representa a una tabla de bd @Table (name= "tb_empleado" ) // Es la tabla que representa esta clase entidad public class Empleado { // // Anotaciones para definir una caracteristica de una columna de bd // @Id // Indica el atributo que representa la PK de la tabla // @Column(name="COD_EMP",unique=true,nullable=false) // Sirve para indicar que el atributo es una columna name: Se va a relacionar con la tabla cuyo campo es COD_EMP, unique: Unicidad de ese atributo, nullable: No permite valore nulos // private int id; // // Usando Estrategias // // 1) Identity: Ya no seteamos id en EmpleadoTest // @Id // @Column(name="COD_EMP",unique=true,nullable=false) // @GeneratedValue(strategy= GenerationType.IDENTITY) // private int id; // // 2) Secuencia: Es una estructura demas de bd. En mysql para implementar una secuencia se debe crear una tabla y en esa tabla se crea un autoincrmentado de secuencia // @Id // @Column(name="COD_EMP",unique=true,nullable=false) // @GeneratedValue(strategy= GenerationType.TABLE, generator="generador") // @TableGenerator(name="generador", table="tb_secuencia", pkColumnName="descripcion",valueColumnName="valor", pkColumnValue="empleado", allocationSize=1) // private int id; // 3) AUTO @Id @Column (name= "COD_EMP" ,unique= true ,nullable= false ) @GeneratedValue (strategy= GenerationType.AUTO, generator= "generador" ) @TableGenerator (name= "generador" , table= "tb_secuencia" , pkColumnName= "descripcion" ,valueColumnName= "valor" , pkColumnValue= "empleado" , allocationSize= 1 ) private int id; // Basic: Es opcional, indica si la columna es un atributo que puede ser almacenada en una bd // length: Longitud de caracteres // insertable: Indica si este campo puede ser insertable (por defecto es true) @Basic @Column (name= "APE_EMP" , length= 45 , nullable= false , insertable= true , updatable= true ) private String apellido; // columnDefinition: Es el fragmento de SQL utlizado para generar el DDL de l acolumna (depende del manejador de base de datos) @Basic @Column (name= "NOM_EMP" ,length= 45 , columnDefinition= "unsigned NOT NULL" , insertable= true , updatable= true ) private String nombre; @Basic @Column (name= "EDA_EMP" ,nullable= false , insertable= true , updatable= true ) private int edad; @Basic @Column (name= "ARE_EMP" ,length= 45 , nullable= false , insertable= true , updatable= true ) private String area; // @Transient: Si no quedemos que se inserte o se actualize en la bd @Transient private String nombreCompleto; public int getId() { return id; } public void setId( int id) { this .id = id; } public String getApellido() { return apellido; } public void setApellido(String apellido) { this .apellido = apellido; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this .nombre = nombre; } public int getEdad() { return edad; } public void setEdad( int edad) { this .edad = edad; } public String getArea() { return area; } public void setArea(String area) { this .area = area; } public String getNombreCompleto() { return getNombre().concat( " " ).concat(getApellido()); } public void setNombreCompleto(String nombreCompleto) { this .nombreCompleto = nombreCompleto; } // Sobreescribir el método toString para realizar pruebas unitarias @Override public String toString() { return "Empleado [id=" + id + ", apellido=" + apellido + ", nombre=" + nombre + ", edad=" + edad + ", area=" + area + ", nombreCompleto=" + getNombreCompleto() + "]" ; } } |
ESTRUCTURA FINAL DEL PROYECTO
1. Descargar el proyecto finalizado desde aquí
No hay comentarios, ¡cuéntame algo!
Me gustaría saber tu opinión. ¡Saludos!