Documentos de Académico
Documentos de Profesional
Documentos de Cultura
GUIA PARA LA CREACION DE SERVICIOS WEB BASADOS EN REST
Esta guía explica cómo desarrollar servicios web RESTful en Java. Usa la referencia JAX‐RS.
Requisitos:
Lenguaje de programación: Java JDK 8
Servidor de aplicaciones: Payara server 5.191
IDE: Eclipse JEE 2019‐03‐R
DBMS: MariaDB
Framework para desarrollo de recursos REST: JAX‐RS
1. REST – Representational State Transfer
1.1. ¿Qué es REST?
REST es un estilo arquitectural que está basado en estándares de la web y el protocolo
HTTP. Este estilo fue descrito inicialmente por Roy Fielding en su tesis doctoral. En una
arquitectura basada en REST cualquier cosa es un recurso. Un recurso es accesado vía
una interface común basado en los métodos del estándar HTTP. En una arquitectura
basada en REST se debe implementar un servidor REST que proporcione acceso a los
recursos. Un cliente REST puede accesar y modificar los recursos REST.
Cada recurso debe soportar las operaciones comunes HTTP. Los recursos son
identificados por IDs globales (que típicamente son URIs)
REST permite que los recursos tengan diferentes representaciones, por ejemplo, texto,
XML, JSON, etc. Los clientes REST pueden preguntar por una representación especifica
vía el protocolo HTTP (negociación de contenidos)
1.2. METODOS HTTP
Los métodos PUT, GET, POST y DELETE son típicamente usados en una arquitectura
basada en REST. A continuación, se explica estas operaciones:
GET define un acceso de lectura del recurso sin efectos secundarios. El recurso
nunca cambia vía una petición GET (idempotente)
PUT crea un nuevo recurso. También debe ser idempotente.
DELETE elimina un recurso. Las operaciones son idempotentes. Pueden repetirse
sin llegar a resultados diferentes.
POST actualiza un recurso existente o crea un nuevo recurso.
1.3. RESTFUL web services
Un servicio web RESTful está basado en métodos HTTP y los conceptos de REST. Un
servicio web RESTful define la base URI para los servicios, los MIME‐types soportados
(XML, text, JSON, user‐defined, …). Tambien define el conjunto de operaciones (POST,
GET, PUT, DELETE) que son soportados.
2. JAX‐RS con Jersey
2.1. JAX‐RS
Java define el soporte REST via el Java Specification Request (JSR) 311. Esta
especificación se llama JAX‐RS (The Java API for RESTful Web Services). JAX‐RS usa
anotaciones para definir la relevancia REST de las clases Java.
2.2. Jersey
La implementación Jersey proporciona una librería para implementar servicios web
RESTful en un contenedor servlet Java. Esta es la implementación de referencia para la
especificación JSR 311.
Jersey proporciona una implementación servlet que escanea clases predefinidas para
identificar recursos RESTful. Se usa anotaciones en las clases y métodos para definir sus
responsabilidades.
La implementación Jersey también proporciona una librería cliente para comunicarse
con un servicio web RESTful.
La URL base de este servlet es:
http://your_domain:port/context‐root/url‐pattern/path_from_rest_class
Este servlet analiza la solicitud HTTP entrante. Selecciona la clase y método correcto
para responder a esta solicitud.
Una aplicación web REST consiste, por lo tanto, en clases de datos (recursos) y servicios.
Estos dos tipos son típicamente mantenidos en diferentes paquetes.
JAX‐RS soporta la creación de XML y JSON vía the Java Architecture for XML Binding
(JAXB)
2.3. Anotaciones JAX‐RS
Las anotaciones más importantes en JAX‐RS se listan en la siguiente tabla:
Tabla 1. Anotaciones JAX‐RS
Anotación Descripción
@PATH(your_path) Establece la ruta a la URL base + /your_path. La URL base está basada en el
nombre de tu aplicación (la raiz del contexto), el servlet y patrón URL del
archivo de configuración web.xml.
@POST Indica que el siguiente método responderá a una solicitud HTTP POST.
@GET Indica que el siguiente método responderá a una solicitud HTTP GET.
@PUT Indica que el siguiente método responderá a una solicitud HTTP PUT.
Tabla 1. Anotaciones JAX‐RS
Anotación Descripción
@DELETE Indica que el siguiente método responderá a una solicitud HTTP DELETE.
@Produces(MediaType.TEXT_PLAIN[, @Produces define que tipo MIME es entregado por un método anotado con
more‐types]) @GET. "text/plain" genera texto plano, otros tipos citamos a
"application/xml" o "application/json".
@Consumes(type[, more‐types]) @Consumes define que tipo MIME es consumido por el metodo.
@PathParam Usado para inyectar valores desde la URL en un método como parámetro. De
esta forma se inyecta por ejemplo el ID de un recurso en el método para que
se obtenga el objeto correcto.
La ruta completa de un recurso está basada sobre la URL base y la anotación @PATH
en la clase.
http://your_domain:port/context-root/url-pattern/path_from_rest_class
NOTA: Para cambiar de puerto por default (8080) en payara modificar el archivo
E:\AppServer\payara5\Payara\domains\domain1\config\domain.xml según se
muestra a continuación:
<network-listeners>
<network-listener protocol="http-listener-1" port="8083" name="http-listener-1" thread-pool="http-
thread-pool" transport="tcp"></network-listener>
Ver lista de puertos abiertos
Netstat –a
3. Creando el primer servicio web RESTful
3.1. Configuración inicial de eclipse
a) Crear un directorio de trabajo (workspace) donde gestionaremos nuestros proyectos,
en nuestro caso D:\apn2019
b) Desempaquetar el archivo Libraries.rar dentro del workspace
c) Ejecutar eclipse y seleccionar el espacio de trabajo definido en el paso a, la vista es la
siguiente:
3.2. Instalación y configuración del servidor de aplicaciones Payara como
contenedor web
En la presente guía usaremos el servidor de aplicaciones Payara (un fork de Payara), sin
embargo, también se puede desarrollar en WildFly, Tomcat o Google App Engine.
a) Instalar Payara, descargar el instalador de https://www.payara.fish/downloads luego
desempaquetar en una unidad de disco con permisos de lectura y escritura.
b) Vamos a configurar el servidor de aplicaciones Payara desde eclipse, para hacer esto
hacemos clic en “No servers are available. Click this link to create a new server” wizard
de la ficha servers:
c) En la ventana New Server ubicar la carpeta Payara y seleccionar el servidor Payara y
presionar next, tal como se muestra a continuación:
d) En la ventana New Server, en la sección Payara location, seleccionar la ubicación de la
carpeta donde se encuentra Payara, como se muestra a continuación:
e) En la misma ventana, de la misma manera seleccionar la ubicación del JDK que tenemos
instalado
f) En Define Payara runtime properties, Define Payara Application Server properties, dejar
todo por default y presionar Finish, en este punto ya se ha configurado Payara en eclipse
y se puede ejecutar.
3.3. Crear el proyecto con soporte RESTful
1. Crear un dynamic web Project, denominado RestLab01
Dejar las configuraciones por default luego next>>next, Seleccionar la casilla
Generate web.xml deploymet descriptor y luego finalizar
2. Dentro de la carpeta Java Resources/src, crear la clase java HolaRest.java, dentro de
una carpeta recursos
El código para esta clase es:
Clase: HolaRest.java
package recursos;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @Date Oct 9, 2018
*/
@Path("/hola")
public class HolaRest {
/**
* Este método es llamado si se solicita un TEXT_PLAIN
*/
@GET
@Path("/gettext")
@Produces(MediaType.TEXT_PLAIN)
public String getPlainTextHola() {
return "Bienvenido a nuestro primer ejemplo en REST usando Jersey";
}
/**
* Este método es llamado si se solicita un XML
*/
@GET
@Path("/getxml")
@Produces(MediaType.TEXT_XML)
public String getXMLHola() {
return "<?xml version=\"1.0\"?>" + "<hola> Hola REST" + "</hola>";
}
/**
* Este método es llamado si se solicita un HTML
*/
@GET
@Path("/gethtml")
@Produces(MediaType.TEXT_HTML)
public String getHtmlHola() {
return "<html> " + "<title>" + "Bienvenidos a REST" + "</title>"
+ "<body><h1>" + "Este es nuestro primer ejemplo en REST usando Jersey"
+ "</h1></body>" + "</html> ";
}
/**
* Este método es llamado si se solicita un JSON*
*/
@GET
@Path("/getjson")
@Produces(MediaType.APPLICATION_JSON)
public String getJsonlHola() {
String json = "{\"id\":1,\"titulo\":\"Bienvenidos a REST\",\"comentario\
":\"Primer ejemplo de REST\"}";
return json;
}
}
3. Configurar la aplicación para soporte JAX‐RS: Una aplicación JAX‐RS consiste de al
menos una clase recurso empaquetada en un archivo .war. Teniendo en cuenta que
los recursos de una aplicación responden a solicitudes desde una URI base, estas se
pueden configurar de dos formas:(Oracle, 2017)
a. Usando la anotacion @ApplicationPath como una subclase del
paquete javax.ws.rs.core.Application empaquetado dentro del
WAR.
b. Usando la etiqueta servlet-mapping dentro del descriptor de despliegue
web.xml dentro del WAR
En la presente guía, a fin de evitar confusiones en la configuración de archivos xml
en proyectos java, utilizaremos anotaciones, creando una clase, tal como se muestra
a continuación:
Clase: HolaApp.java
package recursos;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @Date Oct 9, 2018
*/
@ApplicationPath("/*")
public class HolaApp extends Application{
3.4. Ejecutar el recurso REST
1. Desde el Project explorer en eclipse seleccionar RestLab01, click derecho, Run As,
Run On a Server, y luego presionar Finish, tal como se muestra a continuación:
2. Utilizando la aplicación Insomnia Rest Client (https://insomnia.rest/download/)
vamos a probar los diversos recursos REST desplegados en el servidor Payara, para
acceder a dicho recurso hacerlo utilizando la siguiente URL:
http://localhost:8080/RestLab01/hola/getxml
3. Realicemos las pruebas a los demás recursos REST que se han implementado,
observemos el caso cuando se obtiene un recurso html.
3.5. Crear un cliente REST
La librería Jersey contiene una librería cliente que puede ser utilizada para probar o
construir un cliente real en Java. El uso de esta librería se demuestra a continuación:
Crear un nuevo proyecto Java denominado TestRestLab01, y crear la clase java Test,
dentro del paquete client, para probar los servicios REST desplegados, tal como se
muestra a continuación:
Para poder crear el cliente REST es necesario tener un conjunto de librerías que nos
permita desde el cliente manipular los recursos REST, estas las podemos descargar de:
https://jersey.github.io/download.html
Descargar y desempaquetar la librería Jersey JAX‐RS 2.1 RI bundle (jaxrs‐ri‐2.28.zip) en la
carpeta libraries del workspace en el que estamos trabajando.
Ahora vamos a enlazar la librería a nuestro proyecto, desde las propiedades de nuestro
proyecto en el Java Build Path, add External JARs, agregar todas las librerías, como se
muestra a continuación:
Clase: Test.java
package client;
import java.net.URI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.jersey.client.ClientConfig;
/**
* @author Edwin Valencia Castillo
*
*/
public class Test {
public static void main(String[] args) {
ClientConfig config = new ClientConfig();
System.out.println(response);
System.out.println("\n Resultado en texto plano\n");
System.out.println(plainAnswer);
System.out.println("\n Resultado en xml\n");
System.out.println(xmlAnswer);
System.out.println("\n Resultado en html\n");
System.out.println(htmlAnswer);
System.out.println("\n Resultado en json\n");
System.out.println(jsonAnswer);
}
4. Servicios web RESTful y JAXB
JAX‐RS soporta la creación automática de XML y JSON vía JAXB. A continuación, vamos a
crear un proyecto que despliegue servicios REST desde objetos.
4.1. Creando el proyecto
Con la perspectiva JEE activa, crear un nuevo proyecto (Dynamic Web Project) llamado
RestLab02, el servidor de aplicaciones activo debe ser Payara. El ejemplo a desarrollar
permitirá manejar información de nuestros Contactos.
4.2. Crear las clases Java del dominio
Clase: Contacto.java
package lab.contact.domain;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.Data;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
@XmlRootElement
@Data
public class Contacto {
private int id;
private String nombres;
private String telefono;
private String email;
}
NOTA: La anotación @Data, es implementada por la API Lombok, la cual debe ser
instalada y luego agregada en el Build Path, nos permite gestionar de manera más
adecuada el código boilerplate.
4.3. Crear las clases con soporte RESTful
Crearemos una clase simple que retorne una instancia de la clase Contacto:
Clase: ContactoResource.java
package lab.contacto.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import lab.contacto.domain.Contacto;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
@Path("/contacto")
public class ContactoResource {
/**
* Este método es llamado si se solicita un XML
* */
@GET
@Produces({MediaType.APPLICATION_XML})
/**
* Este método es llamado si se solicita un JSON
* */
@GET
@Produces({MediaType.APPLICATION_JSON})
public Contacto getJSON() {
Contacto contacto = new Contacto();
contacto.setId(1);
contacto.setNombres("Nora");
contacto.setTelefono("90985454");
contacto.setEmail("miemail@contacto.com");
return contacto;
}
/**
* Este metodo puede ser usado para probar la integracion con el browser
* */
@GET
@Produces({ MediaType.TEXT_XML })
public Contacto getHTML() {
Contacto contacto = new Contacto();
contacto.setId(1);
contacto.setNombres("Albert");
contacto.setTelefono("90909454");
contacto.setEmail("miemail@contacto.com");
return contacto;
}
}
También crearemos la clase que iniciara nuestra aplicación con soporte REST.
Clase: ContactoApp.java
package lab.contacto.rest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
@ApplicationPath("/*")
public class ContactoApp extends Application {
}
Ejecutar la aplicación y validar que se tiene acceso al servicio creado. La aplicación debe
estar disponible en la siguiente URL:
http://localhost:8080/RestLab02/contacto
4.4. Crear un cliente para manejar JAXB
Crear un proyecto denominado TestRestLab02, y crear una clase denominada Test.java
dentro de un paquete lab.contacto.test, tal como se muestra a continuación:
Agregar a través del Build Path las librerías jersey necesarias, el código fuente de la clase
que maneja JAXB se describe a continuación:
Clase: Test.java
package lab.contacto.test;
import java.net.URI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
public class Test {
5. CRUD RESTful web services sin acceso a base de datos
En esta sección crearemos un servicio web RESTful con soporte CRUD (Create, Read, update,
Delete). Permitirá mantener la lista de CONTACTOs a través de llamadas HTTP.
5.1. Proyecto
Agregar también la librería lombok, para reducir el código boilerplate.
En el paquete domain, crearemos nuestras clases de dominio (clases persistentes),
resources contendrá las clases que implementaran los servicios web RESTful, el paquete
dao contendrá las clases que permitan manipulara el acceso a datos y en el paquete ejb
contendrá las clases de la lógica del negocio.
5.2. Creando la clase de dominio
A continuación, crearemos una clase de dominio que represente los datos con soporte
JAXB.
Clase: Contacto.java
package lab.contacto.domain;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.Data;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
@XmlRootElement
@Data
public class Contacto {
private int id;
private String nombres;
private String telefono;
private String email;
}
5.3. Creando la clase de acceso a datos
A continuación, en el paquete dao, vamos a crear la clase que permitirá gestionar los
datos de un repositorio, inicialmente, datos estáticos.
Clase: ContactoDAO.java
package lab.contacto.services.dao;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import lab.contacto.domain.Contacto;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
public class ContactoDAO {
public ContactoDAO() {
Contacto contacto1 = new Contacto();
contacto1.setId(1);
contacto1.setNombres("Pepe Cortizona");
contacto1.setTelefono("545432432");
contacto1.setEmail("pepe@condorito.com");
contactosMap.put(1, contacto1);
contactosMap.put(2, contacto2);
contactosMap.put(3, contacto3);
}
5.4. Creando la clase de la lógica del negocio
A continuación, en el paquete service, crearemos la clase encargada de la lógica del
negocio (implementación de casos de uso)
Clase: ContactoEJB.java
package lab.contacto.services.ejb;
import java.util.List;
import lab.contacto.domain.Contacto;
import lab.contacto.services.dao.ContactoDAO;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
public class ContactoEJB {
ContactoDAO contactoDao = new ContactoDAO();
5.5. Creando la clase que implementa el servicio web RESTful
Una vez creadas las clases de acceso datos y de la lógica del negocio, vamos a crear
nuestras clases con soporte a servicio web RESTful.
Clase: ContactoResource.java
package lab.contacto.resources;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import lab.contacto.domain.Contacto;
import lab.contacto.services.ejb.ContactoEJB;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
Para finalizar creamos la clase que se encargara de desplegar los servicios RESTful.
Clase: ContactoApp.java
package lab.contacto.resources;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
/**
* @author Edwin Valencia Castillo
* @version 1.0.0
* @date Oct 9, 2018
*/
@ApplicationPath("/*")
public class ContactoApp extends Application {
}
Ejecutar la aplicación y validar que se tiene acceso al servicio creado. La aplicación debe
estar disponible en la siguiente URL:
Para visualizar todos los contactos: http://localhost:8080/RestLab03/contactos
Para visualizar un contacto específico: http://localhost:8080/RestLab03/contactos/2
El resultado final del proyecto sería:
5.6. Creando un cliente para el manejo de operación CRUD a través de
servicios RESTful
Laboratorio: crear el cliente correspondiente y realizar las pruebas con las operaciones
CRUD a los servicios RESTful.
6. CRUD RESTful web services con acceso a base de datos
En esta sección crearemos un servicio web RESTful con soporte CRUD (Create, Read, update,
Delete). Permitirá mantener la lista de CONTACTOs a través de llamadas HTTP, gestionando
los datos en una base de datos MariaDB. La arquitectura de la aplicación a desarrollar se
muestra a continuación:
6.1. Proyecto
La presente guía, asume el acceso a una base de datos ya existente, por este motivo, y
por motivos académicos vamos a crear una base de datos en el DBMS MYSQL con el
nombre Contactos:
Una vez creada la base de datos, desde eclipse crear una conexión a ésta base de datos:
Activar la perspectiva Database Development, y ejecutar el script que permita crear las
tablas en la base de datos Contactos.
Verificar la creación de las tablas en la base de datos Contactos.
Finalizada la creación de la base de datos, procedemos a crear un nuevo Dynamic Web
Project llamado RestLab04 con la perspectiva JEE, configurar la utilización de la Faceta
JPA y establecer la conexión a la base de datos Contactos, y activando el descriptor de
despliegue web.xml, crear la siguiente estructura de paquetes:
En el paquete domain, crearemos nuestras clases de dominio (persistentes), resources
contendrá las clases que implementaran los servicios web RESTful, el paquete dao
contendrá las clases que permitan manipulara el acceso a datos, el paquete dto
contendrá las clases que permitirán la transferencia de objetos entre nuestra aplicación
y los recursos RESTful y en el paquete ejb contendrá las clases de la lógica del negocio.
6.2. Creando la capa de persistencia
Esta capa contendrá las clases persistentes (dominio), estas clases contienen la
estructura de los datos almacenados en la base de datos, la cual será mapeada y
sincronizada, para crear esta capa se deben seguir los siguientes pasos:
a. Generar las clases entidad desde la conexión a la base de datos, haciendo click
derecho en el paquete domain, seleccionar Generate Entities from Tables,
seleccionado la conexión Contactos:
b. Verificar que las asociaciones entre tablas sea las correctas
c. De ser necesario, configurar la variable Key Generator y verificar que los nombres
de las clases y atributos sean las adecuadas.
d. El IDE crea las clases entidad en el paquete domain, la estructura de las clases se
muestra a continuación:
e. Verificar que el archivo persistence.xml contenga las clases que serán parte del
dominio y que están sincronizándose con la base de datos, además, configurar el
tipo de transacción JTA.
Esta configuración es necesaria cuando se ponga en producción la aplicación en el
servidor de aplicaciones, la aplicación utilizará esta configuración para conectarse
con el JNDI creado en el servidor de aplicaciones, el cual está configurado para
conectarse con el manejador de base de datos, en nuestro caso MariaDB.
f. Debido a que una vez creada la aplicación, ésta estará en producción en el servidor
de aplicaciones, y éste, es el que accederá a los datos en la base de datos, es
necesario establecer una conexión entre el servidor de aplicaciones y la base de
datos, según la propuesta de nuestra arquitectura, esto se realizará a través de JNDI,
para lo cual se ha creado un pool de conexión utilizando JDBC denominado
“contacto_pool”, luego de creado dicho pool, se ha creado un recurso, igualmente
utilizando JDBC, ha dicho recurso se le ha denominado “apiContacto”, este recurso
será utilizado desde nuestra aplicación a través de la configuración JNDI, a
continuación, se muestra como se ha realizado dicha configuración:
La configuración de las variables del poll “contacto_pool” debe ser como se muestra
a continuación:
Nombre de la
Valor Descripción
propiedad
Dirección url donde se encuentra el
URL jdbc:mysql://:3306/contactos
servidor de base de datos es
importante definir el puerto adecuado
Nombre de la
Valor Descripción
propiedad
Es el nombre del servidor, una vez que
se coloque en producción, el nombre
ServerName localhost del servidor tendrá una IP y nombre
definido asignado por el administrador
de infraestructura.
Nombre de la base de datos con la cual
DatabaseName contactos
Payara establecerá conexión.
Nombre del usuario que tiene
User root privilegios de administrador en el
manejador de base de datos
Clave de acceso del usuario, hay que
tener en cuenta que dicha
configuración se realiza en el servidor
Password admin de aplicaciones, por lo que dicha
información está segura, ya que es de
acceso solo del administrador de
aplicaciones.
Para que las configuraciones a las variables no presenten inconvenientes, el
conector para el manejador de base de datos debe estar copiado en el directorio
bin del servidor de aplicaciones Payara.
6.3. Creando la capa de acceso a datos
Una vez culminado la capa de dominio, vamos a crear la capa que permita realizar las
operaciones básicas CRUD para el manejo de la base de datos, este paquete
implementará los EJBs necesarios para implementar las operaciones básicas por cada
clase persistente. La funcionalidad ofrecida por este conjunto de operaciones de EJBs se
corresponde de un modo genérico con el patrón dao (Data Access Object), cuya principal
característica es ocultar las tecnologías y el modo de acceso a los datos, delegando, en
este caso, las operaciones concretas en el componente EntityManager de la API de
persistencia de Java conocida como JPA.
Para desarrollar el acceso de datos en este caso se ha definido una clase DAO genérica
(GenericDAO) la cual implementa las operaciones básicas (crear, buscar por id,
actualizar, borrar y otros métodos comunes a todas las clases entidad) y que serán
necesarias para nuestro proyecto. De esta clase heredan los demás EJBs y sus interfaces,
añadiendo nuevas operaciones, como las operaciones de búsqueda específicas o de la
lógica del negocio.
La convención para el nombrado de las clases es como sigue:
• FilexxxDAO.java: Clase de implementación del EJB (@Stateless o @Stateful)
• FilexxxDAOLocal.java: Interfaz local del EJB (@Local)
A continuación, se presenta el proceso de creación de dicha capa:
a. Crear una interfaz con el siguiente nombre: GenericDAOInterface<T>, el código
será:
Clase: GenericDAOInterface<T>.java
public interface GenericDAOInterface<T> {
public void create(T entity);
public T update(T entity) ;
public void delete(int id);
public T findByID(Object entityID);
public List<T> findAll();
public int count();
}
b. Crear la clase GenericDAO<T> que implemente la interfaz antes creada:
Clase: GenericDAO<T>.java
package com.evc.contacto.services.dao;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
public class GenericDAO<T> implements GenericDAOInterface<T> {
private final static String UNIT_NAME = "RestLab04";
@PersistenceContext(unitName = UNIT_NAME)
protected EntityManager em;
/**
* Crea un nuevo registro en la base de datos para una determinada entidad
* @param entity Información a registrar
* @return Nueva instancia manejada con su ID
*/
@Override
public void create(T entity) {
em.persist(entity);
}
/**
* Elimina un registro de una entidad en la base de datos.
* @param id del registro a eliminar
*/
public void delete(int id) {
@SuppressWarnings("unchecked")
Class<T> entityClass = (Class<T>) ((ParameterizedType)
getClass().getGenericSuperclass()).getActualTypeArguments()[0];
T entity = em.find(entityClass, id);
em.remove(entity);
}
/**
* Actualiza una instancia existente de una entidad.
*
* @param entity Instacia a actualizar
* @return Instancia actualizada
*/
@Override
public T update(T entity) {
return em.merge(entity);
}
/**
* Obtiene una instancia de una entidad dado el ID.
* @param id de la instancia a obtener
* @return Instancia de la entidad manejada
*/
@SuppressWarnings("unchecked")
@Override
public T findByID(Object entityID) {
Class<T> entityClass = (Class<T>) ((ParameterizedType)
getClass().getGenericSuperclass()).getActualTypeArguments()[0];
// Identifica la clase real de las entidades gestionada por este objeto (T.class)
return em.find(entityClass, entityID); //retorna un objeto que coincide con el ID
}
/**
* Obtiene una colección de todas las instancias de una entidad
* @return Colección de instancias de una entidad
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public List<T> findAll() {
Class<T> entityClass = (Class<T>) ((ParameterizedType)
getClass().getGenericSuperclass()).getActualTypeArguments()[0];
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return em.createQuery(cq).getResultList();
}
/**
* Obtiene la cantidad de registros en la base de datos para una determinada entidad
* @return Numero de registros manejados por la entidad
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public int count() {
Class<T> entityClass = (Class<T>) ((ParameterizedType)
getClass().getGenericSuperclass()).getActualTypeArguments()[0];
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
Root<T> rt = cq.from(entityClass);
cq.select(em.getCriteriaBuilder().count(rt));
Query q = em.createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}
c. Una vez creada la clase genérica y su interfaz que implementa los métodos CRUD, a
continuación, creamos una clase Session Bean por cada clase del dominio, tal como
se muestra como ejemplo a continuación:
Clase: CiudadDAOLocal.java
package com.evc.contacto.services.dao;
import javax.ejb.Local;
import com.evc.contacto.domain.Ciudad;
@Local
public interface CiudadDAOLocal extends GenericDAOInterface<Ciudad>{
}
Clase: CiudadDAO.java
package com.evc.contacto.services.dao;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import com.evc.contacto.domain.Ciudad;
/**
* Session Bean implementation class CiudadDAO
*/
@Stateless
@LocalBean
public class CiudadDAO extends GenericDAO<Ciudad> implements CiudadDAOLocal {
/**
* Default constructor.
*/
public CiudadDAO() {
// TODO Auto‐generated constructor stub
}
}
Realizar este paso por cada clase del dominio (clase entidad o clase persistente)
6.4. Creando la capa de negocio y objetos de transferencia de datos
Creado el paquete de acceso a datos e implementadas las funcionalidades que faciliten
el acceso a los datos de las bases de datos, se ha procedido a crear las clases que
implementan la lógica del negocio, sin embargo, para mejorar el acceso a la información,
así como la facilidad en la manipulación de los datos se usa el patrón DTO (Data transfer
object), clases que son similares a las clases entidad, solo que estas no están mapeadas
con la base de datos.
Dentro del paquete dto, crear por cada clase entidad, una clase siguiendo el patrón dto,
tal como se muestra en el siguiente ejemplo:
Clase: CiudadDTO.java
package com.evc.contacto.services.dto;
import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import com.evc.contacto.domain.Ciudad;
import com.evc.contacto.domain.Contacto;
import com.evc.contacto.domain.Pais;
import lombok.Data;
@XmlRootElement
@Data
public class CiudadDTO implements Serializable {
private static final long serialVersionUID = 1L;
private int idCiudad;
private String nombreCiudad;
private Pais pais;
private List<Contacto> contactos;
public CiudadDTO() {
}
/**
* Crea un objeto CiudadDTO a partir de un objeto Ciudad.
*
* @param entity Entidad Ciudad desde la cual se va a crear el nuevo objeto.
* @generated
*/
public CiudadDTO(Ciudad entity) {
if (entity!=null){
this.idCiudad=entity.getIdCiudad();
this.nombreCiudad=entity.getNombreCiudad();
this.contactos = entity.getContactos();
this.pais = entity.getPais();
}
}
/**
* Convierte un objeto CiudadDTO a Ciudad
*
* @return Nuevo objeto Ciudad
* @generated
*/
public Ciudad toEntity() {
Ciudad entity = new Ciudad();
entity.setIdCiudad(idCiudad);
entity.setNombreCiudad(nombreCiudad);
entity.setContactos(contactos);
entity.setPais(pais);
return entity;
}
}
El paquete negocio ofrece soporte a casos de uso un poco más específicos de más alto
nivel que hacen uso los EJBs, dao y dto y que permitirán implementar las funcionalidades
de los servicios REST, a este paquete se le denomina ejb, y donde se implementa la lógica
del negocio más específica, para fines de presentación, a continuación, se presentan el
código fuente de la clase CiudadEJB y CiudadEJBInterface, clase que implementa la
lógica del negocio para la gestión de las ciudades, así como las operaciones CRUD:
Clase: CiudadEJBInterface.java
package com.evc.contacto.services.ejb;
import java.util.List;
import com.evc.contacto.domain.Ciudad;
public interface CiudadEJBInterface {
public int countCiudad();
public List<Ciudad> getCiudades();
public Ciudad getCiudadById(Integer id);
public Ciudad createCiudad(Ciudad entity);
public Ciudad updateCiudad(Ciudad entity);
public void deleteCiudad(Integer id);
}
Clase: CiudadEJB.java
package com.evc.contacto.services.ejb;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Inject;
import com.evc.contacto.domain.Ciudad;
import com.evc.contacto.services.dao.CiudadDAOLocal;
/**
* Session Bean implementation class CiudadEJB
*/
@Stateless
public class CiudadEJB implements CiudadEJBInterface {
@Inject
private CiudadDAOLocal ciudadDAO;
/**
* Default constructor.
*/
public CiudadEJB() {
// TODO Auto‐generated constructor stub
}
@Override
public int countCiudad() {
return ciudadDAO.count();
}
@Override
public List<Ciudad> getCiudades() {
return ciudadDAO.findAll();
}
@Override
public Ciudad getCiudadById(Integer id) {
return ciudadDAO.findByID(id);
}
@Override
public Ciudad createCiudad(Ciudad entity) {
ciudadDAO.create(entity);
return entity;
}
@Override
public Ciudad updateCiudad(Ciudad entity) {
return ciudadDAO.update(entity);
}
@Override
public void deleteCiudad(Integer id) {
ciudadDAO.delete(id);
}
}
6.5. Creando la capa de recursos RESTful
En esta capa se programa la capa de recursos web (RESTful), teniendo en cuenta los
requerimientos de información que se requiere exponer, para ello se ha definido en
primer lugar la url, para nuestro caso ésta será:
http://localhost:8080/Lab04/v1/{recurso_web}
A continuación, se muestra la clase para exponer información de ciudades:
Clase: CiudadResource.java
package com.evc.contacto.resources;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.evc.contacto.domain.Ciudad;
import com.evc.contacto.services.dto.CiudadDTO;
import com.evc.contacto.services.ejb.CiudadEJBInterface;
@Stateless
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/ciudades")
public class CiudadResource {
@Inject
CiudadEJBInterface sciudad;
/**
* Convierte una lista de Ciudad (entidades) a una lista de CiudadDTO.
*
* @param entityList Lista de Ciudad a convertir.
* @return Lista de CiudadDTO convertida.
* @generated
*/
private List<CiudadDTO> listEntity2DTO(List<Ciudad> entityList) {
List<CiudadDTO> list = new ArrayList<>();
for (Ciudad entity : entityList) {
list.add(new CiudadDTO(entity));
}
return list;
}
/**
* Obtiene la lista de los registros de Ciudad
*
* @return Coleccion de objetos de CiudadDTO
*
* @generated
*/
@GET
public List<CiudadDTO> getCiudades(){
return listEntity2DTO(sciudad.getCiudades());
//return sciudad.getCiudades();
}
/**
* Obtiene los datos de una instancia de Ciudad a partir de su ID
*
* @param id Identificador de la instancia a consultar
* @return Instancia de CiudadDTO con los datos de la Ciudad consultada
* @generated
*/
@GET
@Path("/{id: \\d+}")
public CiudadDTO getCiudad(@PathParam("id") int id){
return new CiudadDTO(sciudad.getCiudadById(id));
}
/**
* Se encarga de crear una Ciudad en la base de datos
*
* @param dto Objeto de CiudadDTO con los datos nuevos
* @return Objeto de CiudadDTO con los datos nuevos y su ID
* @generated
*/
@POST
public CiudadDTO createCiudad(CiudadDTO dto) {
return new CiudadDTO(sciudad.createCiudad(dto.toEntity()));
}
/**
* Actualiza la informacion de una instancia de una Ciudad
*
* @param id Identificador de la instancia de la Ciudad a modificar
* @param dto Instancia de CiudadDTO con los nuevos datos
* @return Instancia de CiudadDTO con los datos actualizados
* @generated
*/
@PUT
@Path("{id: \\d+}")
public CiudadDTO updateCiudad(@PathParam("id") int id, CiudadDTO dto) {
Ciudad entity = dto.toEntity();
entity.setIdCiudad(id);
Ciudad oldEntity = sciudad.getCiudadById(id);
entity.setContactos(oldEntity.getContactos());
entity.setPais(oldEntity.getPais());
return new CiudadDTO(sciudad.updateCiudad(entity));
}
/**
* Elimina una instancia de Ciudad de la base de datos
*
* @param id Identificador de la instancia a eliminar
* @generated
*/
@DELETE
@Path("{id: \\d+}")
public void deleteCiudad(@PathParam("id") int id) {
sciudad.deleteCiudad(id);
}
}
Antes de desplegar los recursos RESTful, hay que tener en cuenta que en java el
funcionamiento de los recursos REST, parte de una clase principal, en nuestro caso esa
clase se denomina ContactosApp.java, esta clase hereda las características de la librería
REST de Java denominada: javax.ws.rs.core.Application, ésta librería tiene todas las
funcionalidades para desplegar los recursos REST en un servidor de aplicaciones, esta se
encarga de identificar las clases configuradas como recursos REST y publicarlos en el
servidor.
6.6. Desplegando y probando los recursos
Una vez concluida la programación se procede a realizar el despliegue de los recursos
en el servidor de aplicaciones, para nuestro caso Payara, hay que tener en cuenta que
la configuración del servidor se realizó previamente, y solo hay que ejecutar el servidor
de aplicaciones y publicar la aplicación que ya tiene el soporte para servicios REST, la
imagen que se muestra a continuación, se puede observar los resultados del despliegue,
resaltando la configuración de recurso JNDI a través de JDBC para establecer la conexión
entre el servidor de aplicaciones y el manejador de base de datos a través del pool
“contacto_pool” y el recurso “apiContacto; así también se puede observar nuestra
aplicación corriendo denominada “Lab04”.
6.7. Generando la documentación de la API
Una vez concluido con la implementación, despliegue y prueba de los recursos REST, es
necesario que los usuarios de estos servicios tengan acceso a información de cómo
utilizar dichos recursos REST, específicamente, que recursos están en producción y
cuáles son los recursos que están implementados y se pueden utilizar.
La documentación de los recursos REST están por default publicados en la url para
nuestro ejemplo:
http://localhost:8080/RestLab04/application.wadl (Uso de los recursos)
http://localhost:8080/RestLab04/application.wadl/xsd0.xsd (estructura de los objetos)