¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Java Spring
  3. Parte back de la aplicación
Extrait - Java Spring La base técnica de las aplicaciones Jakarta EE
Extractos del libro
Java Spring La base técnica de las aplicaciones Jakarta EE Volver a la página de compra del libro

Parte back de la aplicación

Descripción del problema

En este capítulo se presenta la parte back de una aplicación con una base de datos SQL. Un capítulo específico se ocupará del equivalente con las bases de datos NoSQL. Usamos SQL con aplicaciones que dependen de una base de datos históricamente SQL o con aplicaciones que cambiarán poco. De hecho, la complejidad de una aplicación basada en una base de datos relacional se debe comparar con el uso directo de una base de datos NoSQL.

Para una base de datos SQL, un ORM (Object Relational Mapping) es una herramienta que permite pasar de un modelo lógico orientado a objetos a un modelo físico relacional. Hay varios, como Hibernate, MyBatis, pero el más utilizado es Hibernate, que a menudo se combina con JPA.

JPA es una API Java que se basa en una implementación de un ORM; usamos JPA con Hibernate. Hibernate añade funcionalidades adicionales. Las anotaciones y las API Hibernate solo se utilizan si las funcionalidades que necesita no están disponibles en JPA.

El ORM es el enlace entre la base de datos y los objetos de Java de más bajo nivel, que se agrupan en la capa llamada «capa de dominio de negocio».

Para casos sencillos, el ORM administra el SQL para intercambios con la base de datos, pero es posible personalizar el SQL para casos complejos. En estos casos,  nos abstraemos totalmente del tipo de base de datos....

Implementación

1. Configuración de una entidad de la capa de dominio

Por ejemplo, para configurar una entidad sencilla de la capa de dominio:

@Entity 
@Table(name = "table_book") 
public class Libro implements Serializable {  
@Id 
@Column(name = "id") 
   private String autor; 
   private int numPaginas; 
   private String titulo; 
   // getters et setters 
  [...] 

Este ejemplo solo muestra las API y las anotaciones JPA porque es un caso sencillo:

Elemento

Significado

@Entity

Indica que se trata de una entidad POJO.

@Table(name = "t_book")

Especifica el nombre de la tabla public class Libro implements Serializable. Una entidad debe ser serializable.

@Id

Indica que el campo será una clave principal.

@Column(name = "id")

Especifica el nombre de la columna que contendrá la clave principal.

private String autor

Datos de negocio

El autor del libro

private int numPaginas

Datos de negocio

El número de páginas

private String titulo

Datos de negocio

El título

No hay ninguna anotación en los datos de negocio porque se trata de un tipo que Hibernate mapea sin dificultad a nivel del tipo y del nombre de la columna. De lo contrario, habríamos añadido una anotación @Column y personalizado la columna.

También es posible tener variables de clase que no están registradas en la base de datos. A continuación, la variable se anota con la anotación @Transient.

Se accede a las clases de la capa de dominio a través de la capa Repository.

Mapping many-to-one y one-to-many

@Entity 
public class Book implements Serializable { 
    @Id 
    private String title; 
    private int nbPage;  
 
 @OneToMany 
 private Set<Chapter> chapters = 
 new HashSet<Chapter>(); 
     // getters et setters 

De forma predeterminada, las relaciones entre objetos son de tipo lazy loading. Esto significa que los datos contenidos en las colecciones solo se recuperan de la base de datos si se accede a ellos. Por lo tanto, es necesario evitar el uso de la palabra clave instanceOf sobre objetos Entity porque es normal que tengamos un proxy en lugar del objeto. Las Entities...

Para ir más allá

Existen frameworks que simplifican enormemente la implementación de un backend, que suele funcionar gracias a las anotaciones de procesadores.

1. Librería Java jcabi-aspects

Esta librería se basa en AspectJ y ofrece algunas anotaciones de AOP cubiertas por Spring o Lombok, como @Async, @Cachable, @Loggable, y otras que faltarían, como @LogExceptions, @Quietly, @RetryOnFailure, @UnitedThrow. La documentación se puede encontrar aquí: https://aspects.jcabi.com/

2. Métricas AspectJ

Hay una librería que permite añadir métricas en nuestros backends a través de anotaciones AspectJ. Permiten tener elementos finos en las llamadas. La documentación está disponible en https://github.com/astefanutti/metrics-aspectj

Usar MapStruct

Hemos visto que nuestro código se organiza en capas. Podemos utilizar el modelo DTO, que consiste en definir clases sencillas para transferir los datos entre capas. Uno de los principales problemas que encontramos es la escritura de una gran cantidad de código de mapeo. Existe una librería de Java MapStruct que permite automatizar, con la generación de código, la fase de mapping a través de la descripción de esta mediante interfaces sencillas y anotaciones sobre las clases. MapStruct se puede utilizar con el CDI de Spring junto con Lombok, creando el Mapper como un bean. La documentación se puede encontrar en https://mapstruct.org/documentation/spring-extensions/reference/html/

1. Enfoque API-First

El diseño de backend para los Web Services SOAP o REST ha existido durante años. Durante mucho tiempo, la API se dedujo de las llamadas codificadas en los backends. Codificamos un servicio y luego añadimos y publicamos la API correspondiente a ese servicio, algunas veces de manera automática. Esto da como resultado API que no siempre son ideales.

Un nuevo enfoque consiste en predefinir la API y, a continuación, codificar la aplicación para representar el servicio llamado.

No hay estándares predefinidos para la API REST. Surgió un primer estándar: Swagger, sustituido más tarde por OpenAPI. Esta normalización o estandarización...

Herramientas

Swagger y OpenAPI tienen una variedad de herramientas que son complementarias. Ambas líneas siguen los mismos estándares.

1. Swagger

Las fuentes están disponibles en GitHub, en la dirección https://github.com/swagger-api. Swagger admite varias herramientas:

Herramientas

Utilidad

Swagger Editor

Editor de API

Swagger UI

Visualización e interacciones con la API

Swagger Codegen

Generadores de código/archivos de API

2. OpenAPITools

Las fuentes están disponibles en GitHub, en la dirección https://github.com/OpenAPITools. OpenAPITools soporta varias herramientas:

Herramientas

Utilidad

OpenAPI Generator

Generadores de código/archivos de API

OpenAPI Style Validator

Cumplimiento de los estándares corporativos

OpenAPI Diff

Comparación de dos especificaciones

3. Otros

Hay otros que se enumeran y se pueden consultar en https://openapi.tools/

Generadores de código

Tanto Swagger como OpenAPI cuentan con una suite de herramientas que permiten, entre otras cosas, generar código a partir de una descripción de API y viceversa. Ya hemos visto el plugin Springfox para generar la descripción de la API, desde el código hasta la compilación, durante el runtime. También tienen herramientas para generar código a partir de la descripción de la API.

La descripción de la API se realiza a través de un archivo JSON o YAML. A partir de este archivo, es posible generar código en diferentes lenguajes y para diferentes servidores. Nos centramos en generar código cliente y servidor con las tecnologías Java y Spring Boot. El generador es polimórfico. Existe en forma de CLI (Command Line Interface) en un JAR, de paquete npm y de plugin maven.

La versión maven es la más sencilla para poder hacer modificaciones. En efecto, tenemos el mismo «problema» que con los generadores de código como jHipster, para los cuales la plantilla que se utiliza para la generación no se corresponde exactamente con los archivos que serían deseables. Los generadores Swagger y OpenAPI no incluyen los mismos conjuntos de templates y cada uno tiene sus características específicas.

Uso del plugin

1. Para el generador Swagger

Configuración maven

<plugin> 
<groupId>io.swagger</groupId> 
<artifactId>swagger-codegen-maven-plugin</artifactId> 
<version>3.8.1</version> 
<executions> 
 <execution> 
  <goals> 
   <goal>generate</goal> 
  </goals> 
  <configuration> 
   <inputSpec>swagger.yaml</inputSpec> 
   <language>java</language> 
   <library>resttemplate</library> 
  </configuration> 
 </execution> 
</executions> 
</plugin> 

2. Para el generador OpenAPITools

Configuración maven

<plugin> 
<groupId>org.openapitools</groupId> 
<artifactId>openapi-generator-maven-plugin</artifactId> 
<version>5.4.0</version> 
<executions> 
 <execution> 
  <goals> 
<goal>generate</goal> 
  </goals> 
  <configuration> 
<inputSpec> 
 ${project.basedir}/src/main/resources/petstore.yml 
</inputSpec> 
<generatorName>spring</generatorName> 
<apiPackage>fr.eni.openapi.api</apiPackage> 
<modelPackage>fr.eni.openapi.model</modelPackage> ...

Personalización

Es posible personalizar los templates que se utilizan para la generación de código. 

1. Swagger

La personalización del generador Swagger es un poco más compleja. La forma más sencilla consiste en parchear un conjunto de plantillas. El motor de plantillas es Mustache.

2. OpenAPITools

La personalización de OpenAPI es relativamente sencilla. Hay varios niveles de personalización, como se indica en el sitio del producto, en la dirección https://openapi-generator.tech/docs/customization/. Funciona bien y el motor de plantillas predeterminado es Mustache.

Diseño de una descripción de API

Si diseña una API que sigue una versión del estándar OpenAPI, no significa necesariamente que será utilizable porque los generadores de código no siempre implementan código que cubra todo el estándar. Se debe probar con las herramientas Swagger y OpenAPI a nivel de la generación de código de los DTO y de los controladores y clientes REST. Se deben probar las diferentes combinaciones Spring MVC/Spring WebFlux y Java/Kotlin en las diferentes versiones de estas. Las API que usan polimorfismo y herencia se deberán probar específicamente.

Si es posible, será necesario indicar las configuraciones probadas con el código generado con su forma de probarlo porque muchos problemas solo se ven en tiempo de ejecución.

Herramientas para el diseño de la API

La herramienta jHipster se puede utilizar para un enfoque API-First (https://www.jhipster.tech/doing-api-first-development/), pero ya debe tener su archivo YAML (o JSON).

No hay muchas herramientas públicas avanzadas que permitan crear un contrato de interfaz de API a partir de un modelo UML o de proyección en el sentido DDD del término.

Herramienta

Sitio

Código abierto

Stoplight

https://stoplight.io/studio

SwaggerHub

https://swagger.io/tools/swaggerhub/

Podemos configurar un modelador UML con generador de código Java para generar clases, anotarlas con anotaciones Swagger API y generar YAML (o JSON) a partir de estas clases personalizando las plantillas.

Spring Actuator

Spring Boot Actuator es un módulo que permite obtener información operativa sobre nuestra aplicación.

Para usarlo con Spring Boot, es suficiente con añadir la dependencia maven:

<dependency> 
   <groupId>org.springframework.boot</groupId> 
   <artifactId>spring-boot-starter-actuator</artifactId> 
</dependency> 

El módulo funciona con las aplicaciones Spring MVC y Spring Webflux y utiliza los endpoints HTTP y JMX para exponer información.

Con Spring Boot 2, solo se exponen los endpoints /health e /info para limitar los problemas de seguridad.

La configuración de la seguridad se puede realizar a través de un bean de configuración:

@Bean 
public SecurityWebFilterChain securityWebFilterChain( 
 ServerHttpSecurity http) { 
   return http.authorizeExchange() 
     .pathMatchers("/actuator/**").permitAll() 
     .anyExchange().authenticated() 
     .and().build(); 
} 

Endpoint

Uso

/auditevents

Enumera los eventos relacionados con la auditoría de seguridad, como la conexión/desconexión. Podemos aplicar filtros.

/beans

Enumera todos los beans disponibles en nuestra BeanFactory. A diferencia de /auditevents, no admite el filtrado.

/condiciones

Crea un informe...

Puntos clave

  • Los objetos de la capa de negocio son objetos de tipo Entity gestionados por una EntityManager.

  • Algunas veces, los objetos están disponibles como proxies.

  • JPA ofrece el uso de múltiples niveles de caché.

  • Podemos tener tipos personalizados.

  • La gestión de concurrentes es ajustable.

  • Mejoraremos la mantenibilidad de la aplicación, respetando el principio de las capas de aplicación.