Tutoriel sur le développement full stack d'une application Web avec Angular 7 et Spring Boot 2


précédentsommairesuivant

XII. Objectifs du front-end

L'application Library développée et présentée dans la page précédente, dispose d'une API REST composée de web services concourant à répondre aux besoins exprimés dans les Users Stories. Dans ce contexte, elle ne peut gagner toute son utilité que s'il existe une ou plusieurs application(s) cliente(s) qui consomme(nt) les web services exposés.

Dans cette partie de notre article, notre objectif est de développer un client web, baptisé Library-ui, qui offrira une vue IHM (Interface Homme Machine) pour la gestion de la bibliothèque. Ce client web sera composé de pages web pour l'administration des livres, des clients et des prêts. Il disposera aussi d'un menu général permettant de naviguer vers les différentes pages. Chacune de ces pages comportera un bouton back permettant de retourner sur le menu général. Library-ui devra être un site web dynamique qui consomme les API REST exposées en back-end dans le projet Library, afin de permettre à l'administrateur de l'application de réaliser tous ses besoins.

Pour ce faire, nous avons sélectionné le framework Angular qui nous permettra d'atteindre cette spécification. Sa version au moment où nous développions cette application était la 7. Au terme de cette partie, nous allons construire une application purement cliente dont la figure ci-dessous illustre les différents composants :

Image non disponible

Les différents composants coloriés en jaune sont les suivants :

  • le composant Book, qui proposera une page web pour la création, mise à jour, lecture et suppression de livres ;
  • le composant Customer, qui proposera une page web pour la création, mise à jour, lecture et suppression de clients ;
  • Le composant Loan, qui proposera une page web pour la création, mise à jour, lecture et suppression de prêts ;
  • le composant menu, pour la gestion du menu général ;
  • le composant modal, incorporé dans le composant Loan, qui proposera une fenêtre modale permettant d'envoyer des mails.

XIII. Mise en place du projet Angular Library-ui

XIII-A. Préambule et notions de base

Angular est un framework basé sur le langage TypeScript (une surcouche du JavaScript). Sa philosophie, comme celle de nombreux frameworks concurrents (Vue.js, React.js, etc.), peut se résumer par la phrase suivante : proposer un nouveau paradigme de construction de sites web qui améliore l'expérience utilisateur. Plus simplement, cela veut dire, l'optimisation du temps de réponse et donc de la performance des pages web visitées par une tierce personne lorsqu'elle navigue sur un site web. Pour atteindre cet objectif, Angular s'appuie sur deux politiques architecturales majeures.

  • La notion de Single Page Application (SPA) : il s'agit d'une approche qui consiste à considérer les différentes pages web d'un site comme des composants devant tous être incorporés dans une seule et unique page principale. Seule cette page principale est reconnue et gérée par le navigateur. Par des mécanismes très poussés que propose le framework, il sera alors possible de jouer sur l'affichage ou pas de différents composants dans cette page principale afin de donner l'impression à l'utilisateur qu'il navigue sur des pages web différentes.
  • La maximisation des traitements côté client : cette approche permet de créer des sites web dynamiques où la grande majorité des traitements derrière tout composant sont exécutés côté client, c'est-à-dire votre navigateur web (Chrome, Mozilla, IE, etc). Seuls les traitements nécessitant la consommation d'une API REST feront appel au serveur en back-end.

La philosophie ci-dessus expliquée du framework Angular se distingue donc de celle des technologies comme JSP/JSTL, PHP, etc., où le serveur héberge plusieurs pages web et se charge de les servir à votre navigateur à chaque requête. Cette approche provoque ainsi une actualisation par rechargement des pages sur le navigateur à la moindre action utilisateur. Ce qui provoque une perte de temps et une navigation dégradée. Or avec la politique SPA, les requêtes du client vers le serveur n'impliquent pas un rechargement de la page principale hébergée sur le serveur. Celle-ci n'est en effet chargée qu'une seule fois lors du démarrage de l'application cliente.

Angular fait partie des frameworks basés sur la plateforme node.js. Node.js est un outil offrant, entre autres, la possibilité de compiler et d'exécuter du code Angular en phase de développement sur un poste de travail. Il s'installe aisément sur votre poste de travail. Angular s'appuie aussi sur le repository npm (désormais intégré dans node.js) pour vous permettre d'installer des modules qui lui permettent de vous offrir de nombreuses fonctionnalités exploitables dans votre projet Angular.

Pour l'installation de node.js/npm, nous vous demandons de suivre le lien suivant https://nodejs.org/fr/ pour télécharger l'installateur et l'installer sur votre machine en suivant les indications.

Enfin, pour développer une application Angular, il faut un IDE (Integrated Developpement Environnement) approprié. Sur Eclipse, il existe le plugin Angular Eclipse d'Angelo Zerr, à installer via la MarketPlace. On peut aussi utiliser l'IDE gratuit Visual Studio Code qui intègre déjà tout le nécessaire pour développer des projets Angular. Enfin, il existe aussi l'IDE payant Angular IDE. Nous faisons le choix pour cet article d'utiliser Visual Studio Code.

Pour terminer cette section, si vous avez besoin de plus d'informations sur la notion de Single Page Application, vous pouvez lire les contenus suivants : Arolla, Octo.

XIII-B. Création du projet Library-ui

Maintenant que vous avez installé node.js/npm et Visual Studio Code pour la plateforme de développement, nous sommes presque prêts pour la création du projet Angular Library-ui. Mais avant cette opération, il est nécessaire d'installer Angular CLI. Angular CLI est un outil permettant de créer et de gérer aisément le cycle de vie d'un projet de type Angular. Toute proportion gardée, on peut voir Angular CLI comme le maven des projets Java. Au moment de développer ce projet, Angular CLI était à la version 7.3.3 correspondant donc à la version 7 du framework Angular. Son installation se réduit à l'instruction suivante dans un terminal et dans n'importe quel répertoire de poste de travail :

 
Sélectionnez
npm install -g @angular/cli@7.3.3

Maintenant nous pouvons donc créer notre projet à l'aide de la commande :

 
Sélectionnez
ng new Library-ui

Le projet imagé sur la figure ci-dessous est donc créé et il ne reste plus qu'à l'ouvrir avec notre IDE pour le compléter. Le répertoire /src représente celui dans lequel nous ajouterons nos codes sources.

Image non disponible

XIII-C. Configuration du projet

Lors de la phase de développement, le framework Angular utilise le port 4200 sur votre localhost pour visualiser en temps réel les IHM développées. L’URL d'accès est donc la suivante : http://localhost:4200.
Nous voulons par ailleurs que notre application soit accessible via le lien http://localhost:4200/library-uilibrary-ui est le point d'entrée de l'application permettant d'afficher le menu. configurer. Enfin, et comme nous l'avons expliqué, notre application Library-ui communiquera avec le back-end à l'aide d'appel REST. Il est donc important que nous vous présentions comment cela est mis en place.

1. Modification du fichier Package.json

Dans le répertoire d'installation du projet Library-ui (voir capture ci-dessus), ouvrez le fichier Package.json et modifiez la ligne coloriée en jaune pour ajouter l'instruction suivante : --base-href /library-ui --proxy-config proxy.conf.json.

Image non disponible
  • La commande --base-href /library-ui, permet de marquer l'accessibilité de la page web principale sur le suffixe /library-ui. Exemple : la saisie de l’URL http://localhost:4200/library-ui permettra d'afficher le menu principal.
  • La commande --proxy-config proxy-conf.json, permet d'indiquer l'adresse des différents serveurs côté back-end auxquels l'application cliente Angular peut être amenée à appeler. En d'autres termes, c'est dans ce fichier que l'on configure les URL des serveurs qui hébergent les API REST auxquels Library-ui va faire appel.

2. Création du fichier proxy-conf.json

Dans le répertoire d'installation du projet Library-ui (voir capture ci-dessus) et au même niveau que le fichier package.json, créez le fichier de nom proxy-conf.json et ajoutez le contenu présenté sur la capture. Pour aller plus loin sur la configuration, vous pouvez consulter le lien suivant. Notez que le contenu de ce fichier indique que le serveur back-end répond sur l'URL http://localhost:8082 en n'admettant uniquement les requêtes http contenant le préfixe /library. Cette configuration s'adapte donc aux URI de nos API REST exposés dans le projet Library côté back-end dans les contrôleurs REST.

Image non disponible

Une fois les deux premières configurations ci-dessus effectuées, ouvrez le fichier angular.json et dans la rubrique serve, ajoutez la commande "proxyConfig": "src/proxy.conf.json". Il suffit de se positionner à la racine du répertoire du projet Library-ui et d'exécuter la commande npm start sur un terminal pour démarrer l'exécution de cette application.

Image non disponible

3. Dossier ressources

Notez, que le projet Library-ui contient un dossier nommé assets obtenu lors de la création du projet à l'aide de la commande ng new… Ce dossier assets est destiné à contenir tous les fichiers ressources de l'application à l'instar des images. C'est ce que nous avons fait en ajoutant l'image que vous visualiserez sur la page de menu de l'application.

4. Configuration du spinner

Nous avons rajouté un spinner dans notre application Library-ui. Cela nécessite d'installer un nouveau module nommé ngx-spinner. Pour rappel, un Spinner est un composant HTML graphique et dynamique qui permet de signaler l'indisponibilité totale d'une page web quand il est en train de charger les éléments constituants son contenu. Pour en savoir plus sur son installation et sa configuration, suivre le lien suivant.

5. Configuration du DatePicker

Sur nos pages HTML, nous aurons besoin d'utiliser des calendriers afin de compléter des champs de saisie avec des dates (ex. : date de sortie d'un livre, date de début d'un prêt, etc.). Pour ce faire, Angular propose un module offrant des outils permettant de gérer aisément l'affichage et la manipulation d'un calendrier dans un élément HTML de type input. Cependant, ce module n'est pas présent dans la liste des modules de base obtenus lors de l'installation de l'Angular CLI. Nous devons donc installer le module Angular Material. Vous pouvez suivre le lien suivant, pour comprendre comment nous l'avons intégré dans notre application.

XIV. Pages web et services HttpClient

Dans cette partie, nous présentons succinctement les trois différentes pages web que nous avons développées pour gérer respectivement les livres, clients et prêts. Nous présentons aussi les services Angular associés permettant de consommer les API REST exposées côté back-end. Comme nous vous l'avons expliqué dans la section précédente, le terme page web est un abus de langage d'un point de vue Angular. En effet, ce framework crée et gère des composants HTML qu'il intègre dans une seule et unique page principale (l'index.html située à la racine du projet). Ainsi donc, dans le sens pur du terme, Angular permet de développer des composants.

Pour créer un composant Angular, allez dans le répertoire library-ui/src/app et saissez la commande suivante :

 
Sélectionnez
ng g component <nom-composant>

Cette commande nous permettra de créer respectivement les composants Book-page, Customer-page, Loan-page, etc. Leurs dossiers respectifs seront générés et contiendront les fichiers d'extension : .html, .css, .ts et .spec.ts. Exemple :

Image non disponible
  • le fichier d'extension .html, est un fichier template qui contient tous les éléments HTML nécessaires à l'affichage du composant ;
  • le fichier d'extension .css, contient les instructions de style pour le .html ;
  • le fichier d'extension .ts, contient une classe dans laquelle nous allons développer nos fonctions TypeScript afin de répondre au besoin métier que doit gérer le composant. Ce fichier .ts contient donc toutes les variables utilisées par le .html pour afficher dynamiquement des données. Par ailleurs, le .html transmettra des informations au .ts à travers l'émission d'évènements basés sur des fonctions développées dans ce dernier. Enfin, notez que ce sont les fonctions développées dans le .ts qui consommeront réellement les API REST exposées côté back-end.
  • le fichier d'extension .spec.ts, correspond au fichier de tests unitaires des fonctions développées dans le .ts

Pour des raisons de clarté architecturale, nous avons créé, pour chaque composant Book-page, Customer-page et Loan-page, une classe de services regroupant les différents appels REST nécessaires à la page. Ainsi donc, le fichier .ts de chaque composant n'aura plus qu'à appeler cette classe pour consommer les différents web service. Pour implémenter nos classes de services, nous avons créer un dossier services dans le répertoire library-ui/src/app et y avons exécuté la commande suivante :

 
Sélectionnez
ng g service <nom-service>

Pour la suite de cette partie, nous vous exposons le rendu de chacun des composants ainsi que la classe de services associée. Nous laissons le soin au lecteur de s'approprier le code source développé dans chacun des composants. Les sources de l'application sont disponibles à la fin de cet article.

XIV-A. Composant Book et ses services d'appel REST

Dans cette section, nous vous présentons la page de gestion des livres que nous avons développée. Vous pourrez retrouver son code source dans le composant src/app/book du projet Library-ui :

Image non disponible

Cette page a pour besoin de consommer les différents web services exposés côté back-end dans le contrôleur BookRestController. La classe de service baptisée BookService définie dans le fichier /src/app/services/book.service.ts, injecte via son constructeur, l'objet HttpClient fourni par Angular afin de pouvoir consommer des web services :

 
Sélectionnez
import { Injectable } from '@angular/core';
import { Observable } from "rxjs";
import { Category } from "src/app/models/category";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Book } from "src/app/models/book";

@Injectable({
  providedIn: 'root'
})
export class BookService {

    constructor(private http: HttpClient) { }
    
    /**
     * Get all book's categories as reference data from Backend server.
     */
     loadCategories(): Observable<Category[]>{
         let headers = new HttpHeaders();
         headers.append('content-type', 'application/json');
         headers.append('accept', 'application/json');
         return this.http.get<Category[]>('/library/rest/category/api/allCategories', {headers: headers});
     }
     
    /**
     * Save a new Book object in the Backend server data base.
     * @param book
     */
     saveBook(book: Book): Observable<Book>{
         return this.http.post<Book>('/library/rest/book/api/addBook', book);
     }
     
     /**
      * Update an existing Book object in the Backend server data base.
      * @param book
      */
      updateBook(book: Book): Observable<Book>{
          return this.http.put<Book>('/library/rest/book/api/updateBook', book);
      }
      
      /**
       * Delete an existing Book object in the Backend server data base.
       * @param book
       */
       deleteBook(book: Book): Observable<string>{
           return this.http.delete<string>('/library/rest/book/api/deleteBook/'+book.id);
       }
     
     /**
      * Search books by isbn
      * @param isbn
      */
     searchBookByIsbn(isbn: string): Observable<Book>{
         return  this.http.get<Book>('/library/rest/book/api/searchByIsbn?isbn='+isbn);
     }
     
    /**
     * Search books by title
     * @param title
     */
     searchBookByTitle(title: string): Observable<Book[]>{
             return this.http.get<Book[]>('/library/rest/book/api/searchByTitle?title='+title);
     }
}

HttPClient fournit entre autres, plusieurs méthodes permettant de faire des appels REST : get(), delete(), put(), post(). Chacune de ces méthodes prend en entrée l'URI du web service concerné et retourne un objet Observable encapsulant l'objet de retour du web service. La classe Observable fournissant de son côté des méthodes permettant d'exploiter l'objet de retour. C'est ce qui est fait dans le fichier book-page.component.ts.

XIV-B. Composant Customer et ses services d'appel REST

Dans cette section, nous vous présentons la page de gestion des clients que nous avons développée. De même, vous pourrez retrouver son code source dans le composant src/app/customer du projet Library-ui :

Image non disponible

Cette page a pour besoin de consommer les différents web services exposés côté back-end dans le contrôleur CustomerRestController. De même la classe de services baptisée CustomerService et définie dans le fichier /src/app/services/customer.service.ts, expose les différents appels :

 
Sélectionnez
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Customer } from '../models/customer';

@Injectable({
  providedIn: 'root'
})
export class CustomerService {

  constructor(private http: HttpClient) { }
        
    /**
     * Save a new Customer object in the Backend server data base.
     * @param book
     */
     saveCustomer(customer: Customer): Observable<Customer>{
         return this.http.post<Customer>('/library/rest/customer/api/addCustomer', customer);
     }
     
     /**
      * Update an existing Customer object in the Backend server data base.
      * @param customer
      */
      updateCustomer(customer: Customer): Observable<Customer>{
          return this.http.put<Customer>('/library/rest/customer/api/updateCustomer', customer);
      }
      
      /**
       * Delete an existing Customer object in the Backend server data base.
       * @param customer
       */
       deleteCustomer(customer: Customer): Observable<string>{
           return this.http.delete<string>('/library/rest/customer/api/deleteCustomer/'+customer.id);
       }
     
     /**
      * Search customer by email
      * @param email
      */
     searchCustomerByEmail(email: string): Observable<Customer>{
         return  this.http.get<Customer>('/library/rest/customer/api/searchByEmail?email='+email);
     }
     
    /**
     * Search books by pagination
     * @param beginPage
     * @param endPage, 
     */
     searchCustomerByLastName(lastName: string): Observable<Customer[]>{
             return this.http.get<Customer[]>('/library/rest/customer/api/searchByLastName?lastName='+lastName);
     }
}

XIV-C. Composant Loan et ses services d'appel REST

Dans cette section, nous vous présentons la page de gestion des prêts que nous avons développée. Le code source qui permet la construction de ce composant est situé dans le dossier src/app/loan du projet Library-ui :

Image non disponible

Cette page a pour besoin de consommer les différents web services exposés côté back-end dans le contrôleur LoanRestController. Sa classe de services baptisée LoanService est définie dans le fichier /src/app/services/loan.service.ts est la suivante :

 
Sélectionnez
import { Injectable } from '@angular/core';
import { SimpleLoan } from '../models/simple-loan';
import { Loan } from '../models/loan';
import { Observable } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Mail } from '../models/mail';

@Injectable({
  providedIn: 'root'
})
export class LoanService {

  constructor(private http: HttpClient) { }
        
    /**
     * Save a new simpleLoan object in the Backend server data base.
     * @param book
     */
    saveLoan(simpleLoan: SimpleLoan): Observable<Loan>{
         return this.http.post<Loan>('/library/rest/loan/api/addLoan', simpleLoan);
     }
       
      /**
       * Close an existing loan object in the Backend server data base.
       * @param loan
       */
      closeLoan(simpleLoan: SimpleLoan): Observable<Boolean>{
           return this.http.post<Boolean>('/library/rest/loan/api/closeLoan/', simpleLoan);
       }
     
     /**
      * Search Loans by email
      * @param email
      */
     searchLoansByEmail(email: string): Observable<Loan[]>{
         return  this.http.get<Loan[]>('/library/rest/loan/api/customerLoans?email='+email);
     }

     /**
      * Search Loans by maximum date
      * @param maxDate
      */
     searchLoansByMaximumDate(maxDate: Date): Observable<Loan[]>{
       let month : string = maxDate.getMonth() < 10 ? '0'+(maxDate.getMonth()+1): ''+(maxDate.getMonth()+1);
       let dayOfMonth : string = maxDate.getDate() < 10 ? '0'+maxDate.getDate(): ''+maxDate.getDate();
       let maxDateStr : string = maxDate.getFullYear() + '-' + month + '-' + dayOfMonth;
      return  this.http.get<Loan[]>('/library/rest/loan/api/maxEndDate?date='+maxDateStr);
  }
     
    /**
     * Send an email to a customer
     * @param mail
     */
    sendEmail(mail: Mail): Observable<boolean>{
      //let headers = new HttpHeaders();
      //headers.append('responseType', 'arraybuffer'); , {headers: headers}
      return this.http.put<boolean>('/library/rest/customer/api/sendEmailToCustomer', mail);
    }
}

XIV-D. Le menu principal

Nous avons développé une page principale servant de menu et permettant de naviguer d'une page à l'autre. Son code source se trouve dans le dossier /src/app/menu/menu. Par contre ce composant ne fait pas d'appel REST. Il n'y a donc pas de classe de service pour cette dernière.

Image non disponible

Dans la page suivante, nous allons vous présenter comment faire un déploiement de notre application (front-end et back-end) sur un serveur Tomcat. Nous vous présenterons aussi une vidéo dans laquelle nous présentons l'application en live.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2019 Georges KEMAYO. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.