Acceso a Datos

2º DAM - Curso 2023-2024

User Tools

Site Tools


apuntes:serviciosweb

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

apuntes:serviciosweb [17/07/2020 10:16] – created Santiago Faciapuntes:serviciosweb [17/07/2020 10:16] (current) – removed Santiago Faci
Line 1: Line 1:
-====== Spring: Creación de servicios web ====== 
  
-==== ¿Qué son los servicios web? ==== 
- 
-Un servicio web es una aplicación que se encuentra en el lado servidor y permite que otra aplicación cliente conecte con ella a través de Internet para el intercambio de información utilizando el protocolo HTTP.  
- 
-Una de las principales características de los servicios web es que no es necesario que ambas aplicaciones (servidor y cliente) estén escritas en el mismo, lo que hace que la interoperabilidad sea máxima. Por ejemplo, podríamos crear un servicio web en Python y utilizarlo conectándonos desde una aplicación móvil con Android, desde otra aplicación programada en Java o incluso desde otro servicio web escrito con .NET. 
- 
-Además, utilizan el protocolo HTTP para el intercambio de información, lo que significa que la conexión se establece por el puerto 80 que es el mismo que utilizan los navegadores y que es prácticamente seguro que se encuentre abierto en cualquier organización protegida por firewall. Esto hace que no sea necesario tener especial cuidado abriendo puertos innecesarios para poder conectarnos a ellos. Antes de la llegada de los servicios web como los conocemos ahora existían otros protocolos más complicados que requerían de servicios y puertos adicionales, incrementando el riesgo de ataques en las organizaciones que los ponían en marcha. 
- 
-<figure> 
-{{ web_service_internet.jpg }} 
-<caption>Esquema de funcionamiento de un servicio web</caption> 
-</figure> 
- 
-==== REST Web Service ==== 
- 
-Los Servicios Web REST son Servicios Web que cumplen una serie de requisitos según un patrón de arquitectura definida hacia el año 2000 y que se ha extendido siendo el patrón predominante a la hora de implementar este tipo de aplicaciones. 
- 
-Básicamente consiste en seguir una serie de reglas que definen dicha arquitectura. Entre ellas están el uso del procotolo HTTP por ser el más extendido a lo largo de Internet en la actualidad. Además, cada recurso del servicio web tiene que ser identificado por una dirección web (una URL) siguiendo una estructura determinada. Además, la respuesta tendrá que tener una estructura determinada en forma de texto que normalmente vendrá en alguno de los formatos abiertos más conocidos como XML o JSON. 
- 
-<figure> 
-{{ urls.png }} 
-<caption>Ejemplos de URLs que definen el acceso a las operaciones de un servicio web REST</caption> 
-</figure> 
- 
-Esas URLs y su estructura son lo que definen lo que se conoce como la API del Servicio Web, que son las diferentes operaciones a las que los clientes tienen acceso para comunicarse con el mismo. En este caso se trata de una API Web. 
- 
-=== Web API === 
- 
-Una Web API es una API (Application Programming Interface) implementada para un Servicio Web de forma que éste puede ser accesible mediante el protocolo HTTP, en principio por cualquier cliente web (navegador) aunque existen librerías que permiten que cualquier tipo de aplicación (escritorio, web, móvil, otros servicios web, . . .) accedan a la misma para comunicarse con dicho servicio web. 
- 
-La Web API es una de las partes de los Servicios Web que, tal y como comentabamos anteriormente, mejoran sustancialmente la interoperabilidad de éstos con los potenciales clientes ya que permiten que sólo haya que implementar un único punto de entrada para comunicarse con el servicio web independientemente del tipo de aplicación que lo haga. De esa manera el desarrollador del Servicio Web define la lógica de negocio en el lado servidor y los diferentes clientes que quieran comunicarse con el mismo lo hacen a través de la Web API realizando solicitudes a las diferentes URLs que definen las operaciones disponibles. 
- 
-<figure> 
-{{ web_api2.png }} 
-<caption>Arquitectura de aplicación web sin API</caption> 
-</figure> 
- 
-<figure> 
-{{ web_api.png }} 
-<caption>Arquitectura de aplicación web con API</caption> 
-</figure> 
- 
-=== JSON === 
- 
-<code java> 
-{ 
-  "firstName": "John", 
-  "lastName": "Smith", 
-  "isAlive": true, 
-  "age": 25, 
-  "address": { 
-    "streetAddress": "21 2nd Street", 
-    "city": "New York", 
-    "state": "NY", 
-    "postalCode": "10021-3100" 
-  }, 
-  "phoneNumbers": [ 
-    { 
-      "type": "home", 
-      "number": "212 555-1234" 
-    }, 
-    { 
-      "type": "office", 
-      "number": "646 555-4567" 
-    }, 
-    { 
-      "type": "mobile", 
-      "number": "123 456-7890" 
-    } 
-  ], 
-  "children": [], 
-  "spouse": null 
-} 
-</code> 
- 
-===== Spring framework ===== 
- 
-<figure> 
-{{ spring-logo.png }} 
-<caption>Framework Spring</caption></figure> 
- 
-[[http://www.spring.io|Spring]] es un framework de Java para el desarrollo de aplicaciones web. En nuestro caso, lo que queremos construir es una pequeña aplicación web que nos permita disponer de servicios web para comunicar nuestra aplicación con una Base de Datos y que podamos, si asi lo queremos, proporcionar algo de lógica en el lado servidor cuando sea necesario. Para eso utilizaremos //Spring Boot// que es una parte de este framework que facilita bastante el trabajo para casos como el que a nosotros nos interesa. 
- 
-Para eso, lo primero que haremos será utilizar el [[http://start.spring.io|Spring Initializr]] para preparar el proyecto inicial sobre el que luego diseñaremos nuestra pequeña aplicación web. Para ello podemos seguir el videotutorial que aparece al final de este apartado. 
- 
-Una vez tengamos creado el proyecto inicial, podemos empezar a trabajar en él para tener nuestro servidor. En este caso se trata de crear un servidor que tendrá los servicios web necesarios para que los usuarios de una aplicación Android puedan registrar sus opiniones en nuestra Base de Datos. Así, otros usuarios podrán visualizarlas en sus terminales. 
- 
-==== Configuración del servidor ==== 
- 
-Lo primero de todo será editar el fichero de configuración del proyecto para personalizarlo a nuestro caso: 
- 
-<file java application.properties> 
-# Configuración para el acceso a la Base de Datos 
-spring.jpa.hibernate.ddl-auto=none 
-spring.jpa.properties.hibernate.globally_quoted_identifiers=true 
-# Puerto donde escucha el servidor una vez se inicie 
-server.port=${port:8080} 
- 
-# Datos de conexion con la base de datos MySQL 
-spring.datasource.url=jdbc:mysql://localhost:3306/opiniones 
-spring.datasource.username=root 
-spring.datasource.password= 
-spring.datasource.driverClassName=com.mysql.jdbc.Driver 
-</file> 
- 
-Sobre el fichero ''build.gradle'' tendremos que realizar algunos cambios: 
- 
-<file java build.gradle> 
-. . . 
-apply plugin: 'java' 
-apply plugin: 'idea' 
-apply plugin: 'spring-boot' 
-apply plugin: 'war' 
- 
-jar { 
-  baseName = 'opiniones' 
-  version = '0.0.1' 
-} 
- 
-repositories { 
-  mavenCentral() 
-} 
- 
-dependencies { 
-  compile('org.springframework.boot:spring-boot-starter-web') 
-  compile('org.springframework.boot:spring-boot-starter-data-jpa') 
-  compile('mysql:mysql-connector-java:5.1.16') 
-  providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") 
-} 
- 
-configurations { 
-  providedRuntime 
-} 
-</file> 
- 
-Ahora, modificaremos la clase principal ''Application''. De esta forma podremos iniciar nuestro servidor directamente desde la consola de IntelliJ o bien contenida dentro de un servidor de aplicaciones como //Tomcat//, aunque no lo haremos así en este caso. 
- 
-Conviene prestar atención a los comentarios que he dejado en esta clase, donde se explica cómo lanzar la aplicación servidor una vez que este lista. 
- 
-<file java Application.java> 
-/** 
- * Clase que lanza la aplicación 
- * 
- * Cómo compilar/ejecutar la aplicación: 
-  - Si se hacen cambios en el build.gradle conviene ejecutar (desde la terminal): 
-      - ./gradlew idea 
-      - ./gradlew build 
-  - Una vez compilado se pueden ejecutar por dos vias 
-      - ./gradlew bootRun 
-      - También se puede ejecutar el jar (con java -jar) que se genera en la carpeta 'build/libs' según el fichero 'build.gradle' 
- * 
-  El proyecto parte de un proyecto base creado con la herramienta Spring Initializr, 
-  disponible en https://start.spring.io/. Conviene seleccionar ya de inicio las dependencias de Web, JPA y MySQL 
-  De todas formas se pueden añadir luego a gradle y sincronizar el proyecto como se indica más arriba 
- * 
- * @author Santiago Faci 
- * @version curso 2015-2016 
- */ 
-@SpringBootApplication 
-public class Application extends SpringBootServletInitializer { 
- 
-  public static void main(String[] args) { 
-    SpringApplication.run(Application.class, args); 
-  } 
- 
-  @Override 
-  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
-    return application.sources(applicationClass); 
-  } 
- 
-  private static Class<Application> applicationClass = Application.class; 
-} 
-</file> 
- 
-==== Definir la Base de Datos ==== 
- 
-Hay que tener en cuenta que //Spring// utiliza por debajo el framework de //Hibernate// para trabajar con la Base de Datos. Eso nos va a permitir trabajar con nuestras clases Java directamente sobre la Base de Datos, ya que será //Hibernate// quién realizará el mapeo entre el objeto Java (y sus atributos) y la tabla de MySQL (y sus columnas) a la hora de realizar consultas, inserciones, modificaciones o borrados. 
- 
-A continuación se muestra el script ''SQL'' que creará la tabla de la base de datos que usaremos para este ejemplo. Y más adelante la clase Java que se utilizará para hacer el mapeo con dicha tabla. 
- 
-<file sql opiniones.sql> 
-CREATE DATABASE IF NOT EXISTS opiniones; 
-USE opiniones; 
- 
-CREATE TABLE IF NOT EXISTS opiniones ( 
-  id INT UNSIGNED PRIMARY KEY, 
-  titulo VARCHAR(50) NOT NULL, 
-  texto VARCHAR(50), 
-  fecha DATETIME, 
-  puntuacion INT UNSIGNED 
-); 
-</file> 
- 
-Así, simplemente tenemos que crear la clase con los atributos y métodos que queramos y añadir las anotaciones que orientarán a //Hibernate// para saber a qué tabla corresponden los objetos de la clase y a qué columnas sus atributos. 
- 
-<code java> 
-import javax.persistence.*; 
-/** 
- * Opinion que los usuarios tienen sobre un monumento 
- * Se deben definir las anotaciones que indican la tabla y columnas a las que 
- * representa esta clase y sus atributos 
- * 
- * @author Santiago Faci 
- * @version curso 2015-2016 
- */ 
-@Entity 
-@Table(name = "opiniones") 
-public class Opinion { 
- 
-  @Id 
-  @GeneratedValue 
-  private int id; 
-  @Column 
-  private String titulo; 
-  @Column 
-  private String texto; 
-  @Column 
-  private Date fecha; 
-  @Column 
-  private int puntuacion; 
- 
-  // Constructor 
-  // Getters y Setters 
-  . . . 
-} 
-</code> 
- 
-> **Recordad que todas las anotaciones Java en el ejemplo anterior son clases que pertenecen al paquete 'javax.persistence'. Tened cuidado de no importar las mismas clases que existen en otros paquetes, aunque estén relacionados con Spring** 
- 
-==== El Acceso a la Base de Datos ==== 
- 
-Ahora creamos la ''interface'' donde se definirán los métodos que permitirán acceder a la Base de Datos. En este caso nos basta con definir las cabeceras de los mismos, puesto que se trata de una ''interface''. Será el framework el que se encargue de su implementación. En este caso hemos definido métodos para obtener todas las puntuaciones y otro para obtener las que tengan una puntuación determinada. Además, podremos contar con que tenemos las operaciones que nos permiten registrar/modificar (''save'') y eliminar (''delete'') información de la Base de Datos. 
- 
-<code java> 
-/** 
- * Clase que hace de interfaz con la Base de Datos 
- * Al heredar de CrudRepository se asumen una serie de operaciones 
- * para registrar o eliminar contenido (save/delete) 
- * Se pueden añadir operaciones ya preparadas como las que hay de ejemplo ya hechas 
- * 
- * @author Santiago Faci 
- * @version curso 2015-2016 
- */ 
-public interface OpinionRepository extends CrudRepository<Opinion, Integer> { 
- 
-  List<Opinion> findAll(); 
-  List<Opinion> findByPuntuacion(int puntuacion); 
-} 
-</code> 
- 
-==== Implementación del Controller ==== 
- 
-Por último, crearemos la clase que hará de ''Controller'' de la aplicación. En ella introduciremos los métodos con las operaciones que queremos que nuestros usuarios puedan realizar, programaremos la lógica que necesitemos y accederemos a los datos a través del ''OpinionRepository'' que hemos creado en el paso anterior. 
- 
-En este caso hemos creado tres operaciones: 
- 
-  * getOpiniones(): Devuelve todas las opiniones de la base de datos 
-  * getOpiniones(int puntuacion): Devuelve las opiniones que tienen una determinada puntuacion 
-  * addOpinion(String titulo, String texto, int puntuacion): Registra una nueva opinión en la base de datos 
- 
-Cada una de las operaciones tienen una URL de mapeo que nos permite acceder a las mismas desde cualquier cliente (navegador, aplicación Java, aplicación Android). Por ejemplo, si quisieramos obtener todas las opiniones que tienen una determinada puntuación utilizaríamos la siguiente URL: http://localhost:8082/opiniones_puntuacion?puntuacion=4 (cambiando ''localhost'' por la IP o nombre del servidor que corresponda en cada caso). Más adelante se verá cómo hacerlo desde una aplicación Android pero es posible probar nuestro servidor accediendo a estas URLs directamente desde el navegador, de forma que podamos comprobar que todo funciona correctamente antes de seguir. 
- 
-  * http://localhost:8080/opiniones 
-  * http://localhost:8080/opiniones_puntuacion 
-  * http://localhost:8080/opiniones_puntuacion?puntuacion=4 
-  * http://localhost:8080/add_opinion?titulo=eltitulo&texto=eltexto&puntuacion=10 
- 
-<code java> 
-/** 
- * Controlador para las opiniones 
- * Contendrá todos los métodos que realicen operaciones sobre opiniones de los usuarios 
- * 
- * @author Santiago Faci 
- * @version curso 2015-2016 
- */ 
-@RestController 
-public class OpinionController { 
- 
-  @Autowired 
-  private OpinionRepository repository; 
- 
-  /** 
-   * Obtiene todas las opiniones de los usuarios 
-   * @return 
-   */ 
-  @RequestMapping("/opiniones") 
-  public List<Opinion> getOpiniones() { 
- 
-    List<Opinion> listaOpiniones = repository.findAll(); 
-    return listaOpiniones; 
-  } 
- 
-  /** 
-   * Obtiene todas las opiniones con una puntuacion determinada 
-   * @param puntuacion 
-   * @return 
-   */ 
-  @RequestMapping("/opiniones_puntuacion") 
-  public List<Opinion> getOpiniones(int puntuacion) { 
- 
-    List<Opinion> listaOpiniones = repository.findByPuntuacion(puntuacion); 
-    return listaOpiniones; 
-  } 
- 
-  /** 
-   * Registra una nueva opinión en la Base de Datos 
-   * @param titulo 
-   * @param texto 
-   * @param puntuacion 
-   */ 
-  @RequestMapping("/add_opinion") 
-  public void addOpinion(@RequestParam(value = "titulo", defaultValue = "nada") String titulo, 
-                         @RequestParam(value = "texto" , defaultValue = "nada mas") String texto, 
-                         @RequestParam(value = "puntuacion", defaultValue = "-1") int puntuacion) { 
- 
-    Opinion opinion = new Opinion(); 
-    opinion.setTitulo(titulo); 
-    opinion.setTexto(texto); 
-    opinion.setFecha(new Date(System.currentTimeMillis())); 
-    opinion.setPuntuacion(puntuacion); 
- 
-    repository.save(opinion); 
-  } 
-} 
-</code> 
- 
-==== Ejecución del servidor ==== 
- 
-Una vez terminado todo, para lanzar el servidor tenemos dos opciones: 
-  * Desde el propio IDE, ejecutando ''./gradlew bootRun'' (o bien ''gradlew bootRun'' si estamos en Windows) 
-  * Utilizando el jar que podemos generar con el comando ''./gradlew jar build'' (''gradlew jar build'' en Windows) y ejecutarlo con el comando ''java -jar''. El ''.jar'' generado lo podremos encontrar en la carpeta ''build/libs'' 
- 
-{{ youtube>TBIzVT5dHC4 }} \\ 
- 
-==== Depuración de Servicios Web ==== 
- 
-La primera aproximación a la hora de depurar los Servicios Web desarrollados es utilizar el navegador introduciendo las URLs esperando obtener la salida apropiada y comprobar asi que todo funciona correctamente. Es bastante cómodo pero fácil de usar y eficiente, hasta un punto. 
- 
-Si lo que queremos es depurar totalmente, y de una forma profesional, nuestros Servicios Web, tenemos que usar aplicaciones destinadas para ese propósito, como [[https://www.getpostman.com|Postman]], que es una aplicación destinada exclusivamente a testear APIs. 
- 
-<figure> 
-{{ postman.png }} 
-<caption>Postman</caption></figure> 
apuntes/serviciosweb.1594980961.txt.gz · Last modified: 17/07/2020 10:16 by Santiago Faci