Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Java Spring
  3. Partie back de l’application
Extrait - Java Spring Le socle technique des applications Jakarta EE (4e édition)
Extraits du livre
Java Spring Le socle technique des applications Jakarta EE (4e édition) Revenir à la page d'achat du livre

Partie back de l’application

Description de la problématique

Ce chapitre présente la partie arrière d’une application avec une base SQL. Un chapitre dédié traitera de l’équivalent avec les bases NoSQL. Nous utilisons SQL avec des applications qui s’appuient sur une base de données historiquement SQL ou avec des applications qui changeront peu. En effet, la complexification d’une application basée sur une base de données relationnelle est à mettre en regard avec l’utilisation directe d’une base NoSQL.

Pour une base SQL, un ORM (Object Relational Mapping) est un outil qui permet de passer d’un modèle logique objet vers un modèle physique relationnel. Il en existe plusieurs comme Hibernate, MyBatis mais le plus utilisé est Hibernate qui est souvent couplé avec JPA.

JPA est une API Java qui s’appuie sur une implémentation d’un ORM, nous utilisons JPA avec Hibernate. Hibernate apporte des fonctionnalités supplémentaires. Les annotations et API Hibernate ne sont utilisées que si les fonctionnalités dont on a besoin ne sont pas disponibles par JPA.

L’ORM fait le lien entre la base de données et les objets Java de plus bas niveaux que l’on regroupe dans la couche dite « couche de domaine métier ».

Pour les cas simples, l’ORM gère le SQL pour...

Mise en œuvre

1. Configuration d’une entité de la couche domaine

Par exemple, pour configurer une entité simple de la couche domaine :

@Entity 
@Table(name = "table_book") 
public class Livre implements Serializable {  
@Id 
@Column(name = "id") 
   private String auteur; 
   private int nbPage; 
   private String titre; 
   // getters et setters 
  [...] 

Cet exemple ne montre que des API et des annotations JPA car c’est un cas simple :

Élément

Signification

@Entity

Indique qu’il s’agit d’une entité POJO.

@Table(name = "t_book")

Indique le nom de la table public class Livre implements Serializable. Une entité doit être sérialisable.

@Id

Indique que le champ sera une clé primaire.

@Column(name = "id")

Indique le nom de la colonne qui contiendra la clé primaire.

private String auteur

Donnée métier

L’auteur du livre

private int nbPage

Donnée métier

Le nombre de pages

private String titre

Donnée métier

Le titre

Il n’y a pas d’annotation sur les données métier car il s’agit d’un type qu’Hibernate mappe sans difficulté au niveau du type et du nom de la colonne. Dans le cas contraire, nous aurions ajouté une annotation @Column et personnalisé la colonne.

Il est aussi possible d’avoir des variables de classe qui ne sont pas enregistrées dans la base de données. On annote alors la variable avec l’annotation @Transient

Les classes de la couche domaine sont accédées via la couche Repository.

Mapping many-to-one et 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 

Par défaut, les relations entre objets sont du type lazy loading. Cela signifie que les données contenues dans les collections ne sont remontées de la base que si on y accède. Il faut donc éviter d’utiliser...

Pour aller plus loin

Il existe des frameworks qui simplifient grandement la mise en place d’un backend qui fonctionne souvent grâce aux annotations processors.

1. Librairie Java jcabi-aspects

Cette librairie basée sur AspectJ offre certaines annotations d’AOP couvertes par Spring ou Lombok comme @Async, @Cachable, @Loggable et d’autres qui manqueraient comme : @LogExceptions, @Quietly, @RetryOnFailure, @UnitedThrow. La documentation se trouve ici : https://aspects.jcabi.com/

2. Métriques AspectJ

Il existe une librairie qui permet d’ajouter des métriques dans nos backends via des annotations AspectJ. Elles permettent d’avoir des éléments fins sur les appels. La documentation est disponible ici : https://github.com/astefanutti/metrics-aspectj

Utilisation de MapStruct

Nous avons vu que notre code est organisé en couches. Nous pouvons utiliser le modèle DTO, qui consiste à définir des classes simples pour transférer des données entre les couches. Un des principaux problèmes que l’on rencontre réside dans l’écriture d’une grande quantité de code de mappage. Il existe une bibliothèque Java MapStruct qui permet d’automatiser, via de la génération de code, la phase de mapping à travers la description de celle-ci par des interfaces simples et des annotations sur les classes. MapStruct peut s’utiliser avec le CDI de Spring conjointement avec Lombok en créant sous la forme d’un bean le Mapper. La documentation se trouve ici : https://mapstruct.org/documentation/spring-extensions/reference/html/

1. Approche API-First

La conception de backend pour des Web Services SOAP ou REST existe depuis des années. Pendant très longtemps l’API était déduite des appels codés dans les backends. Nous codons un service et nous ajoutons et publions ensuite, parfois de manière automatisée, l’API correspondant à ce service. Il en résulte des API qui ne sont pas toujours idéales.

Une nouvelle approche consiste à prédéfinir l’API pour ensuite coder l’application pour qu’elle rende...

Les outils

Swagger et OpenAPI ont chacun une panoplie d’outils qui sont complémentaires. Les deux lignées suivent les mêmes standards.

1. Swagger

Les sources sont disponibles sur GitHub ici : https://github.com/swagger-api

Swagger supporte plusieurs outils :

Outils

Utilité

Swagger Editor

Editeur d’API

Swagger UI

Visualisation et interactions avec l’API

Swagger Codegen

Générateurs de code/fichier d’API

2. OpenAPITools

Les sources sont disponibles sur GitHub ici : https://github.com/OpenAPITools

OpenAPITools supporte plusieurs outils :

Outils

Utilité

OpenAPI Generator

Générateurs de code/fichier d’API

OpenAPI Style Validator

Pour suivre les standards d’entreprise

OpenAPI Diff

Comparaison de deux spécifications

3. Autres

Il en existe d’autres qui sont listés et visibles ici : https://openapi.tools/

Les générateurs de code

Swagger et OpenAPI ont tous les deux une suite d’outils qui permettent, entre autres, de générer du code depuis une description d’API et réciproquement. Nous avons déjà vu le plugin Springfox pour générer la description de l’API depuis le code, à la compilation et au runtime. Ils ont aussi des outils pour générer du code à partir de la descripion de l’API.

La description de l’API se fait à travers un fichier JSON ou un fichier YAML. À partir de ce fichier, il est possible de générer du code dans différents langages et pour différents serveurs. Nous nous concentrons sur la génération de code client et serveur avec les technologies Java et Spring Boot. Le générateur est polymorphe. Il existe sous la forme d’une CLI (Command Line Interface) dans un JAR, d’un paquet npm et d’un plugin maven.

La version maven est la plus simple pour pouvoir apporter des modifications. Nous avons en effet le même "problème" qu’avec les générateurs de code comme jHipster pour lesquels le modèle utilisé pour la génération ne correspond pas exactement aux fichiers que l’on souhaiterait. Les générateurs Swagger et OpenAPI n’ont pas les mêmes jeux de templates et ont chacun...

Utilisation du plugin

1. Pour le générateur Swagger

Configuration 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. Pour le générateur OpenAPITools

Configuration 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>...

Personnalisation

Il est possible de personnaliser les templates qui sont utilisés pour la génération du code.

1. Swagger

La personnalisation du générateur Swagger est un peu plus complexe. Le plus simple est de patcher un jeu de templates. Le moteur de template est Mustache.

2. OpenAPITools

La personnalisation pour l’OpenAPI est relativement simple. Il existe plusieurs niveaux de personnalisation comme indiqué sur le site du produit : https://openapi-generator.tech/docs/customization/. Cela fonctionne bien et le moteur de template est Mustache par défaut.

Conception d’une description API

Si l’on conçoit une API qui suit une version de la norme OpenAPI, cela ne signifie pas forcément qu’elle sera utilisable, car les générateurs de code n’implémentent pas toujours du code qui couvre l’intégralité de la norme. Il faut la tester avec les outils Swagger et OpenAPI, au niveau de la génération du code des DTO mais aussi des contrôleurs et des clients REST. Il faudrait tester des combinatoires Spring MVC/Spring WebFlux, Java/Kotlin, dans les différentes versions de ces derniers. Les API qui utilisent le polymorphisme et l’héritage devront être particulièrement testées.

Il faudra indiquer les configurations testées avec si possible le code généré avec sa façon de le tester car beaucoup de problèmes ne se voient qu’au runtime.

Outillage pour le design de l’API

L’outil jHipster peut être utilisé pour une approche API-First (https://www.jhipster.tech/doing-api-first-development/) mais il faut déjà avoir son fichier YAML (ou JSON).

Il n’existe pas beaucoup d’outils publics poussés qui permettent de créer un contrat d’interface d’API à partir d’un modèle UML ou de projection au sens DDD du terme.

Outil

Site

Open source

Stoplight

https://stoplight.io/studio

Oui

SwaggerHub

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

Oui

Nous pouvons configurer un modeleur UML avec générateur de code Java pour générer des classes, les annoter avec les annotations Swagger API et générer le YAML (ou JSON) depuis ces classes en personnalisant les templates.

Spring Actuator

Spring Boot Actuator est un module qui permet d’obtenir des informations opérationnelles sur notre application.

Pour l’utiliser avec Spring Boot, il suffit d’ajouter la dépendance maven :

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

Le module fonctionne avec les applications Spring MVC et Spring Webflux et il utilise les endpoints HTTP et JMX pour exposer les informations.

Avec Spring Boot 2, seuls les endpoints /health et /info sont exposés pour limiter les problèmes de sécurité.

La configuration de la sécurité peut être faite via un bean de configuration :

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

Endpoint

Usage

/auditevents

Liste les événements liés à l’audit de sécurité tels que la connexion/déconnexion de l’utilisateur. Nous pouvons appliquer des filtres.

/beans

Liste tous les beans disponibles dans notre BeanFactory. Contrairement à...

Points clés

  • Les objets de la couche métier sont des objets de type Entity gérés par un EntityManager.

  • Les objets sont parfois disponibles sous forme de proxy.

  • JPA propose l’utilisation de plusieurs niveaux de cache.

  • Nous pouvons avoir des types personnalisés.

  • La gestion des accès concurrents est réglable.

  • Nous améliorerons la maintenabilité de l’application en respectant le principe des couches applicatives.