universidad don bosco facultad de estudios … · coordinaciÓn de computaciÓn y mÓviles ciclo ii...
Post on 07-Aug-2020
5 Views
Preview:
TRANSCRIPT
UNIVERSIDAD DON BOSCO
FACULTAD DE ESTUDIOS TECNOLÓGICOS
COORDINACIÓN DE COMPUTACIÓN Y MÓVILES
Ciclo II
Desarrollo de aplicaciones con Web Frameworks
Guía de Laboratorio No. 03
WebServices
I. OBJETIVOS.
Que el alumno cree un servicio web Restful simple
Que el alumno conozca los conceptos de REST
Que el alumno utilice distintos clientes para consumir los webservices de tipo RESTful.
II. INTRODUCCION
REST define un set de principios arquitectónicos por los cuales se diseñan servicios web
haciendo foco en los recursos del sistema, incluyendo cómo se accede al estado de dichos
recursos y cómo se transfieren por HTTP hacia clientes escritos en diversos lenguajes.
REST emergió en los últimos años como el modelo predominante para el diseño de
servicios. De hecho, REST logró un impacto tan grande en la web que prácticamente logró
desplazar a SOAP y las interfaces basadas en WSDL por tener un estilo bastante más
simple de usar.
Los 4 principios de REST
Una implementación concreta de un servicio web REST sigue cuatro principios de diseño
fundamentales:
Utiliza los métodos HTTP de manera explícita
No mantiene estado
Expone URIs con forma de directorios
Transfiere XML, JavaScript Object Notation (JSON), o ambos
Una de las caraterísticas claves de los servicios web REST es el uso explícito de los
métodos HTTP, siguiendo el protocolo definido por RFC 2616. Por ejemplo, HTTP GET se
define como un método productor de datos, cuyo uso está pensado para que las aplicaciones
cliente obtengan recursos, busquen datos de un servidor web, o ejecuten una consulta
esperando que el servidor web la realice y devuelva un conjunto de recursos.
REST hace que los desarrolladores usen los métodos HTTP explícitamente de manera que
resulte consistente con la definición del protocolo. Este principio de diseño básico establece
una asociación uno-a-uno entre las operaciones de crear, leer, actualizar y borrar y los
métodos HTTP. De acuerdo a esta asociación:
• se usa POST para crear un recurso en el servidor
• se usa GET para obtener un recurso
• se usa PUT para cambiar el estado de un recurso o actualizarlo
• se usa DELETE para eliminar un recurso
III. PROCEDIMIENTO
Herramientas a utilizar: Jersey
Para ésta guía haremos uso de la API para
servicios RESTful llamada Jersey. La versión que
utilizaremos es la 2.19 (rama 2.x)
Nota: Utilizaremos el gestor de dependencias
Maven para descargar las librerías
correspondientes.
https://jersey.java.net/download.html
Maven
Apache Maven es una herramienta de gestión y
comprensión de proyectos de software. Basándose
en el concepto de un modelo de objeto de
proyecto (POM), Maven puede gestionar la
compilación, los informes y la documentación de un proyecto a partir de una pieza central
de información.
Vamos a crear un proyecto en formato Maven->Archetype Webapp
Lo nombraremos serviciorest. Procure mantener el nombre del paquete sv.edu.udb.
Agregaremos las librerías para proyectos web, desde Add Library y seleccione
ApacheTomcat (La versión de tomcat que esté utilizando), JRE System Library (La que
tenga instalada en su ordenador).
A continuación editaremos nuestro archivo pom (definición de dependencias de maven).
Agregaremos las dependencias que necesitamos en la sección “dependencies”
Y vamos a agregar nuestras dependencias:
<!-- AGREGAREMOS NUESTRAS DEPENDENCIAS --> <!-- MYSQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency>
<!-- JAX-RS --> <dependency> <groupId>javax.ws.rs</groupId> <artifactId>javax.ws.rs-api</artifactId> <version>2.0.1</version> </dependency> <!-- JERSEY 2.19 --> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> <version>2.19</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-server</artifactId> <version>2.19</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-client</artifactId> <version>2.19</version> </dependency> <!-- JACKSON el parser json --> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jackson</artifactId> <version>2.19</version> <scope>runtime</scope> </dependency> <!-- JACKSON anotaciones 2.5.1 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.5.1</version> <type>jar</type> </dependency> <!-- FIN DE NUESTRAS DEPENDENCIAS -->
Ahora debemos indicar el servlet de Jersey que va a responder a las peticiones. Debe crear
un web.xml (si no existiera) y agregarlo en las definiciones de servlets junto con el servlet
mapping al que responderá:
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>sv.edu.udb.serviciorest</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Es importante respetar el package que buscará jersey para levantar los servicios:
sv.edu.udb.serviciorest
Si cambia este paquete, procure modificarlo en la definición del servlet para que
apunte a las clases respectivas.
Vamos a crear una clase dentro del paquete sv.edu.udb.edu.serviciorest que desplegará un
mensaje corto y también por medio de otra URI, mostrará un listado de “mensajes”. Este
será de hecho nuestro primer servicio.
HelloJersey.java
No olvide guardarlo dentro del paquete sv.edu.udb.serviciorest;
package sv.edu.udb.serviciorest;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("hello")
public class HelloJersey {
@GET
@Produces(MediaType.APPLICATION_JSON)
public String getMessage(){
return "Hello World !! - Jersey 2";
}
@GET
@Path("mensajes")
@Produces(MediaType.APPLICATION_JSON)
public Response getMensajes(){
List<Mensaje> mensajes = new ArrayList();
for(int i=0; i<=10;i++){
Mensaje m = new Mensaje();
m.setNumero(i);
m.setMensaje("Mensaje # " + i);
mensajes.add(m);
}
return Response.status(200).entity(mensajes).build();
}
/**
* Esta es una clase de ejemplo, que vamos a instanciar
* dentro del for y mostraremos en el webservice
*/
class Mensaje{
private int numero;
private String mensaje;
/**
* @return the numero
*/
public int getNumero() {
return numero;
}
/**
* @param numero the numero to set
*/
public void setNumero(int numero) {
this.numero = numero;
}
/**
* @return the mensaje
*/
public String getMensaje() {
return mensaje;
}
/**
* @param mensaje the mensaje to set
*/
public void setMensaje(String mensaje) {
this.mensaje = mensaje;
}
}
}
Ejecute (Run) en el proyecto.
Ahora puede ver los resultados testeando desde el navegador:
http://localhost:8080/serviciorest/rest/hello http://localhost:8080/serviciorest/rest/hello/mensajes
La segunda URI debe entregarle un json.
Puede incluir algún plugin a su navegador por ejemplo descargue e instale en chrome: json
viewer
Vamos a crear la base de datos de gatos:
-- ----------------------------------------------------------------
-- DATABASE presupuesto
-- ----------------------------------------------------------------
CREATE DATABASE presupuesto
CHARACTER SET `latin1`
COLLATE `latin1_swedish_ci`;
Use presupuesto;
-- ---------------------------------------------------------------- -- TABLE categoria -- ---------------------------------------------------------------- CREATE TABLE presupuesto.categoria ( id int(11) NOT NULL AUTO_INCREMENT, nombre varchar(1000) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL, PRIMARY KEY(id) );
-- ----------------------------------------------------------------
-- TABLE concepto
-- ----------------------------------------------------------------
CREATE TABLE `concepto` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nombre` varchar(1000) DEFAULT NULL,
`categoria_id` int(11) DEFAULT NULL,
`valor` double DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `concepto_ibfk_1` (`categoria_id`),
CONSTRAINT `concepto_ibfk_1` FOREIGN KEY (`categoria_id`) REFERENCES
`categoria` (`id`)
) ;
insert into categoria (id, nombre) values (1,'Salidas'),(2,'Recibos');
Para este apartado utilizaremos JDBC para comunicarnos con nuestra base de datos. Vamos
a generar nuestros DAOs (Data Access Object) o Models para acceder a la información.
Cree el paquete sv.edu.udb.model
Crearemos nuestro Pojo Categoria.java:
package sv.edu.udb.model;
public class Categoria {
private int id;
private String name;
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
Y Nuestro Pojo Concepto.java
package sv.edu.udb.model;
public class Concepto {
private int id;
private String name;
private double value;
private int categoryId;
private Categoria category;
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the value
*/
public double getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(double value) {
this.value = value;
}
/**
* @return the categoryId
*/
public int getCategoryId() {
return categoryId;
}
/**
* @param categoryId the categoryId to set
*/
public void setCategoryId(int categoryId) {
this.categoryId = categoryId;
}
/**
* @return the category
*/
public Categoria getCategory() {
return category;
}
/**
* @param category the category to set
*/
public void setCategory(Categoria category) {
this.category = category;
}
}
A continuación requerimos de nuestra configuración de conexión. No usaremos DataSource
aunque puede implementarlo si lo desea.
AppConnection.java
package sv.edu.udb.model;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class AppConnection {
// JDBC driver name and database URL
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/presupuesto";
// Database credentials
static final String USER = "root";
static final String PASS = "";
Connection conn = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet resultSet = null;
public AppConnection(){
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException ex) {
Logger.getLogger(AppConnection.class.getName()).log(Level.SEVERE, null,
ex);
}
}
public void connect() throws SQLException{
conn = DriverManager.getConnection(DB_URL,USER,PASS);
}
public void close() throws SQLException{
if(conn != null){
conn.close();
conn = null;
}
}
}
Vamos a generar nuestro CategoriasDAO.java que realizará dos operaciones únicamente.
Listar y Buscar por id:
package sv.edu.udb.model;
import java.sql.SQLException;
import java.util.ArrayList;
public class CategoriasDAO extends AppConnection{
/**
* This method inserts into gastos table a new row. ;)
* @param categoria
* @throws SQLException
*/
public void insert(Categoria categoria) throws SQLException{
connect();
pstmt = conn.prepareStatement("insert into categoria (nombre) values(?)");
pstmt.setString(1, categoria.getName());
pstmt.execute();
close();
}
/**
* Update all fields from categoria table using its id
* @param categoria
* @throws SQLException
*/
public void update(Categoria categoria) throws SQLException{
connect();
pstmt = conn.prepareStatement("update categoria set nombre = ? where id = ?");
pstmt.setString(1, categoria.getName());
pstmt.execute();
close();
}
/**
* Deletes a categoria by id
* @param id
*/
public void delete(int id) throws SQLException{
connect();
pstmt = conn.prepareStatement("delete from categoria where id = ?");
pstmt.setInt(1, id);
pstmt.execute();
close();
}
/**
* Returns the list of categorias from table.
* @return
* @throws SQLException
*/
public ArrayList<Categoria> findAll() throws SQLException{
connect();
stmt = conn.createStatement();
resultSet = stmt.executeQuery("select id, nombre from categoria");
ArrayList<Categoria> categorias = new ArrayList();
while(resultSet.next()){
Categoria tmp = new Categoria();
tmp.setId(resultSet.getInt(1));
tmp.setName(resultSet.getString(2));
categorias.add(tmp);
}
close();
return categorias;
}
/**
* Find a categoria and returns it using the concepto id
* @param id
* @return
* @throws SQLException
*/
public Categoria findById(int id) throws SQLException{
Categoria categoria = null;
connect();
pstmt = conn.prepareStatement("select id, nombre from categoria where id = ?");
pstmt.setInt(1, id);
resultSet = pstmt.executeQuery();
while(resultSet.next()){
categoria = new Categoria();
categoria.setId(resultSet.getInt(1));
categoria.setName(resultSet.getString(2));
}
close();
return categoria;
}
}
Ahora crearemos ConceptosDAO.java que realizará las 4 operaciones de un CRUD y
adicionalmente la operación de buscar por id:
package sv.edu.udb.model;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
public class ConceptosDAO extends AppConnection{
/**
* This method inserts into Concepto table a new row. ;)
* @param concepto
* @throws SQLException
*/
public void insert(Concepto concepto) throws SQLException{
connect();
pstmt = conn.prepareStatement("insert into concepto (nombre,valor, categoria_id)
values(?,?,?)", Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, concepto.getName());
pstmt.setDouble(2, concepto.getValue());
pstmt.setInt(3, concepto.getCategoryId());
pstmt.executeUpdate();
//obteniendo el ultimo id generado
ResultSet keys= pstmt.getGeneratedKeys();
keys.next();
int id = keys.getInt(1);
concepto.setId(id);
close();
}
/**
* Update all fields from concepto table using its id
* @param concepto
* @throws SQLException
*/
public void update(Concepto concepto) throws SQLException{
connect();
pstmt = conn.prepareStatement("update concepto set nombre = ? , valor = ? ,
categoria_id = ? where id = ?");
pstmt.setString(1, concepto.getName());
pstmt.setDouble(2, concepto.getValue());
pstmt.setInt(3, concepto.getCategoryId());
pstmt.setInt(4, concepto.getId());
pstmt.executeUpdate();
close();
}
/**
* Deletes a Concepto by id
* @param id
*/
public void delete(int id) throws SQLException{
connect();
pstmt = conn.prepareStatement("delete from concepto where id = ?");
pstmt.setInt(1, id);
pstmt.execute();
close();
}
/**
* Returns the list of Conceptos from table.
* @return
* @throws SQLException
*/
public ArrayList<Concepto> findAll() throws SQLException{
connect();
stmt = conn.createStatement();
resultSet = stmt.executeQuery("select id, nombre, valor, categoria_id from
concepto");
ArrayList<Concepto> conceptos = new ArrayList();
while(resultSet.next()){
Concepto tmp = new Concepto();
tmp.setId(resultSet.getInt(1));
tmp.setName(resultSet.getString(2));
tmp.setValue(resultSet.getDouble(3));
tmp.setCategoryId(resultSet.getInt(4));
conceptos.add(tmp);
}
close();
return conceptos;
}
/**
* Find a concepto and returns it using the concepto id
* @param id
* @return
* @throws SQLException
*/
public Concepto findById(int id) throws SQLException{
Concepto concepto = null;
connect();
pstmt = conn.prepareStatement("select id, nombre, valor, categoria_Id from
concepto where id = ?");
pstmt.setInt(1, id);
resultSet = pstmt.executeQuery();
while(resultSet.next()){
concepto = new Concepto();
concepto.setId(resultSet.getInt(1));
concepto.setName(resultSet.getString(2));
concepto.setValue(resultSet.getDouble(3));
concepto.setCategoryId(resultSet.getInt(4));
}
close();
return concepto;
}
}
Ahora vamos a crear nuestros servicios.
Debe agregarlo en el paquete sv.edu.udb.serviciorest;
Cree una clase denominada CategoriasRest. Esta clase tendrá 2 endpoints, uno para listar
todas las categorias /categorias y otra para listar categorías en por su id /categorias/{id}
package sv.edu.udb.serviciorest;
import java.sql.SQLException;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import sv.edu.udb.model.Categoria;
import sv.edu.udb.model.CategoriasDAO;
@Path("categorias")
public class CategoriasRest {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getCategorias() throws SQLException{
CategoriasDAO categoriasDAO = new CategoriasDAO();
List<Categoria> categorias = categoriasDAO.findAll();
return Response.status(200).entity(categorias).build();
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getByCategoriasId(@PathParam("id") int id) throws SQLException{
CategoriasDAO categoriasDAO = new CategoriasDAO();
Categoria categoria = categoriasDAO.findById(id);
if(categoria == null){
return Response.status(404).build();
}
return Response.status(200).entity(categoria).build();
}
}
Los endpoints serán:
http://localhost:8080/serviciorest/rest/categorias
http://localhost:8080/serviciorest/rest/categorias/{id}
En este punto detenga el server tomcat y ejecute el proyecto para refrescar.
Respecto a los conceptos, vamos a crear un servicio que realice las 4 operaciones básicas.
Create, Read, Update, Delete.
ConceptosRest.java
package sv.edu.udb.serviciorest;
import java.sql.SQLException;
import java.util.List;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import sv.edu.udb.model.CategoriasDAO;
import sv.edu.udb.model.Concepto;
import sv.edu.udb.model.ConceptosDAO;
@Path("conceptos")
public class ConceptosRest {
ConceptosDAO conceptosDAO = new ConceptosDAO();
CategoriasDAO categoriasDAO = new CategoriasDAO();
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getConceptos() throws SQLException{
List<Concepto> conceptos = conceptosDAO.findAll();
return Response.status(200).entity(conceptos).build();
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
public Response getConceptosById(@PathParam("id") int id) throws SQLException{
Concepto concepto = conceptosDAO.findById(id);
if(concepto == null){
return Response.status(404)
.header("Access-Control-Allow-Origin", "*")
.entity("Concepto no encontrado").build();
}
return Response.status(200)
.header("Access-Control-Allow-Origin", "*")
.entity(concepto).build();
}
@POST
@Produces(MediaType.APPLICATION_JSON)
public Response insertConcepto(
@FormParam("name") String name,
@FormParam("value") Double value,
@FormParam("category_id") int category_id
) throws SQLException{
Concepto concepto = new Concepto();
if(categoriasDAO.findById(category_id)==null){
return Response.status(400)
.header("Access-Control-Allow-Origin", "*")
.entity("Categoria no corresponde a ninguna existencia").build();
}
concepto.setName(name);
concepto.setValue(value);
concepto.setCategoryId(category_id);
conceptosDAO.insert(concepto);
return Response.status(201)
.header("Access-Control-Allow-Origin", "*")
.entity(concepto)
.build();
}
//@DELETE
@POST
@Produces(MediaType.APPLICATION_JSON)
@Path("delete/{id}")
public Response eliminarConcepto(
@PathParam("id") int id
) throws SQLException{
Concepto concepto = conceptosDAO.findById(id);
if(concepto == null){
return Response.status(400)
.entity("Concepto no corresponde a ninguna existencia")
.header("Access-Control-Allow-Origin", "*")
.build();
}
conceptosDAO.delete(id);
return Response.status(200)
.header("Access-Control-Allow-Origin", "*")
.entity(concepto)
.build();
}
@POST
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
public Response updateConcepto(
@PathParam("id") int id,
@FormParam("name") String name,
@FormParam("value") Double value,
@FormParam("category_id") int category_id
) throws SQLException{
Concepto concepto = conceptosDAO.findById(id);
if(concepto == null){
return Response.status(404)
.header("Access-Control-Allow-Origin", "*")
.entity("Concepto no corresponde a ninguna existencia")
.build();
}
if(categoriasDAO.findById(category_id)==null){
return Response.status(400)
.header("Access-Control-Allow-Origin", "*")
.entity("Categoria no corresponde a ninguna existencia")
.build();
}
concepto.setName(name);
concepto.setValue(value);
concepto.setCategoryId(category_id);
conceptosDAO.update(concepto);
return Response.status(200)
.header("Access-Control-Allow-Origin", "*")
.entity(concepto)
.build();
}
}
En este punto detenga el server tomcat y ejecute el proyecto para refrescar.
Ahora utilizaremos una aplicación llamada postman. Descárguela e iníciela.
Vamos a hacer una nueva petición tipo post para agregar un concepto. Para realizar las
peticiones, puede guiarse del formulario presentado a continuación:
Nuestra respuesta debe verse como la siguiente:
Ahora modificaremos un elemento. Haga una consulta tipo get para ver los IDs existentes y
luego actualice uno de ellos.
Finalmente eliminaremos el elemento. Identifique con un ID el elemento que desea
eliminar, realizará una petición de tipo post.
¿Porqué no utilizó PUT y DELETE?.
Aunque debería ser lo ideal, algunos clientes http pueden carecer de estas funciones. (Por
ejemplo formularios en html y sin usar javascript), por ello, se hizo una modificación para
poder utilizar actualizar y eliminar mediante POST
IV. ANALISIS DE RESULTADOS
1. La guía de laboratorio muestra un campo vacío. ¿Es posible obtener los datos de la categoría a la que pertenece? ¿De qué manera?
2. Crear un webservice para dar mantenimiento (ingresar, eliminar, listar, actualizar) una tabla de su Taller MVC. Crear su respectivo cliente (puede usar php, jquery, etc).
3. Investigue qué es documentar una API Rest. Documente su api de Taller MVC.
HOJA DE EVALUACIÓN
Actividad a
evaluar Criterio a evaluar
Cumplió Puntaje
SI NO
Discusión de
resultados
Realizó los ejemplos de guía de práctica
(40%)
Presentó todos los problemas resueltos
(20%)
Funcionan todos correctamente y sin errores
(30%)
Envió la carpeta comprimida y organizada
adecuadamente en subcarpetas de acuerdo al
tipo de recurso (10%)
PROMEDIO:
Investigación
complementari
a
Envió la investigación complementaria en la
fecha indicada (20%)
Resolvió todos los ejercicios planteados en la
investigación (40%)
Funcionaron correctamente y sin ningún
mensaje de error a nivel de consola o
ejecución (4 0%)
PROMEDIO:
Hoja de cotejo:
3
Alumno: Carnet:
Docente: Fecha:
Título de la guía: No.:
top related