Aller au contenu

Exercice 1 - Développement de l'application - V1.0⚓︎

Ça y est, on peut commencer à développer notre application.

1. Création du projet⚓︎

Créer un projet, qu'on appelera boutique.

Création du projet

Comme dans le TD1, auquel on pourra se reporter si besoin, on utilisera Maven et l'archetype webapp-jakartaee10.

  • Le group id sera toujours fr.univtours.polytech.
  • L'artefact id sera donc boutique (c'est toujours le nom du projet).
  • Dans le fichier pom.xml, ne pas oublier d'ajouter <finalName>boutique</finalName> dans la balise <build>.

2. Implémentation du modèle⚓︎

Dans cette première version, le modèle n'est constitué que d'une seule classe, qui modéliser le panier. Il s'agit d'un bean. Nous l'appellerons CartBean.

Remarque

Il est pratique d'indiquer ce qu'est la classe dans son nom, ici, un bean (exactement comme ce que nous avons fait précédemment pour les Servlets).

  1. Il faut tout d'abord créer le package qui va contenir le modèle : fr.univtours.polytech.boutique.model.
  2. Dans ce package, créer la classe CartBean. C'est un bean, c'est-à-dire qu'elle doit implémenter l'interface java.io.Serializable. Il faut donc l'ajouter.
  3. Dans ce bean, il faut créer tous les attributs :
    ☕ Code Java
    1
    2
    3
    4
    5
    6
    private Integer penNumber;    // Le nombre de stylo.
    private Integer feltNumber;   // Le nombre de feutre.
    private Integer rubberNumber; // Le nombre de gomme.
    private Double cartPrice;     // Le prix du panier.
    private Double shippingCost;  // Les éventuels frais de livraison.
    private Double totalPrice;    // Le prix total.
    
  4. Il faut ensuite générer les getters/setters. Le menu Sources Actions... permet d'automatiser tout cela.
Astuce : bonnes pratiques

Prenez l'habitude, à chaque modification d'une classe, de faire deux choses :

  1. AltShifto : Permet de faire du ménage dans les imports pour ne conserver que ceux utiles.
    Les import java.io.* par exemple sont remplacés par l'import des classes utilisées uniquement.
  2. CtrlShifti : Permet de formater le code, de la même façon pour tout le monde.
    C'est vraiment un plus si le code de tout le monde est formaté de la même façon. Cela permet de le comprendre beaucoup plus rapidement !
Ne pas utiliser de tabulations

De manière générale, quel que soit le langage (Java, Python, XML, ...) il faut remplacer les Tab par des espaces.

3. Implémentation de la couche métier⚓︎

Par rapport au paradigme MVC, on peut considérer que cette couche fait partie du modèle. En effet, son rôle est de mettre à jour ce dernier.

La couche métier

Cette couche est la couche centrale de l'application. Lorsqu'on la développe, on se demande quels sont les services métiers qu'elle doit fournir. Ici, il y en a un seul, il s'agit de calculer les différents prix affichés sur le panier, c'est-à-dire d'appliquer les 3 règles de gestions.

De manière générale, c'est dans cette couche que les différentes règles de gestion seront implémentées.

La couche métier est toujours accessible via une interface. Cette interface indique la liste des services disponibles. Depuis l'extérieur, c'est-à-dire depuis le contrôleur, on souhaite savoir quels sont les services offerts (l'interface), mais on ne veut pas savoir comment ils sont implémentés (la classe qui implémente cette interface).

Nous allons donc créer une interface, proposant une méthode computePrices, qui va prendre le panier en paramètre, appliquer les 3 règles de gestions, et renvoyer le panier mis à jour. Cette interface va être implémentée par une classe.

  1. Créer le package représentant la couche métier : fr.univtours.polytech.boutique.business.
  2. Créer l'interface permettant d'exposer les services : StoreBusiness.
  3. Elle contient une méthode computePrices, qui prend un objet CartBean (le panier) en paramètre, et qui renvoie ce même objet modifié :
    ☕ Code Java
    1
    public CartBean computePrices(CartBean cart);
    
  4. Dans ce même package, créer une classe StoreBusinessImpl, qui implémente cette interface.
  5. Une erreur apparaît. En effet la méthode computePrices, qui doit être implémentée, est absente.

    Pour l'ajouter automatiquement, il est possible de placer le curseur sur l'erreur, puis avec CtrlShift;, de sélectionner Add unimplemented methods. 7. Cette classe va contenir 3 champs statiques, qui correspondent au prix de nos trois produits :

    ☕ Code Java
    1
    2
    3
    private final static Double PEN_PRICE = 1.2D;
    private final static Double FELT_PRICE = 1.8D;
    private final static Double RUBBER_PRICE = 2D;;
    
    8. Enfin, voici une grande partie de l'implémentation de la méthode computePrices :
    ☕ Code Java - Méthode computePrices de StoreBusinessImpl
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    // Application de la RG1 :
    Double cartPrice = cart.getPenNumber() * PEN_PRICE + ...;
    // Application de la RG2 :
    Double shippingCost = 5D;
    if (cartPrice > ...) {
        shippingCost = ...;
    }
    // Application de la RG3 :
    Double totalPrice = ...;
    
    // Mise à jour du panier :
    cart.setCartPrice(cartPrice);
    ...
    ...
    
    return cart;
    

    Rappel des 3 règles de gestion

    Pour rappel, les trois RG sont :

    • RG1 : Calcul du prix du panier, sachant que :
      • un styo coûte 1,20€,
      • un feutre coûte 1,80€,
      • une gomme coûte 2€.
    • RG2 : Les frais de livraison sont de 5€ si la commande est de moins de 15€, et sont offerts sinon.
    • RG3 : Le prix total de la commande est la somme du prix du panier et des évenutels frais de livraison.
    Remarque

    Lorsqu'on fait un copier/coller du code, les imports ne sont pas toujours faits. S'il y a des erreurs (CartBean est par exemple inconnu), pensez à faire un CtrlAltO pour les mettre à jour !

  6. Compléter les ... dans la méthode computePrices pour appliquer correctement les 3 RG.

C'est bon, notre modèle est en place.

4. Implémentation du contrôleur⚓︎

Nouvelle version de JEE

JEE, pour Java Entreprise Edition, a changé de nom après la version 8. À partir de la version 9, JEE signifie Jakarta Entreprise Edition.

Il n'y a pas que le nom qui a changé, tous les packages qui commencait par javax commencent maintenant par jakarta. Par exemple, javax.servlet.http.HttpSession a été renommé en jakarta.servlet.http.HttpSession.

Le contrôleur est une servlet. Une servlet est une classe qui hérite de HttpServlet de l'API servlet. Il y a ensuite deux façons de déployer une servlet :

  • Via le descrtipteur de déploiement, c'est-à-dire le fichier 📄web.xml (c'est ce que nous avons vu dans le cours).
  • Via des annotations (c'est ce que nous avons toujours fait en TD).
Remarque importante !

Dans tous les cas, on choisit une seule de ces deux méthodes, jamais les deux.

  1. Créer le package : fr.univtours.polytech.boutique.controller.
  2. Créer la Servlet : StoreServlet.
  3. Indiquer qu'elle étend HttpServlet.
  4. Déployer la Servlet en ajoutant l'annotation. L'url pour y acceder sera /store
  5. Surcharger la méthode doGet (via Source Actions...). N'oublie pas de renommer les paramètres req et resp.

    Note

    La servlet n'implémentant que cette méthode, cela signifie qu'elle ne va pouvoir intercepter que les requêtes HTTP dont la méthode est GET. Comme nous le verrons juste après, si nous envoyons une requête HTTP POST, nous obtiendrons une erreur.

    Rappel sur les méthodes HTTP
    • La méthode GET est la méthode par défaut lorsqu'on exécute une requête HTTP depuis son navigateur, c'est-à-dire lorsqu'on saisit l'URL dans la barre du navigateur et qu'on appuie sur Entrée.

      On peut envoyer des paramètres au serveur qui traite cette requete en ajoutant les couples (clef, valeur) dans l'URL, après un ?, séparés par des &.

      Par exemple : http://url_de_mon_appli?param1=valeur1&param2=valeur2&...

    • La méthode POST est appelée lorsqu'on soumet un formulaire, afin d'envoyer des valeurs au serveur, c'est-à-dire lorsqu'on clique sur un bouton. Les paramètres sont alors placés dans le corps de la requête.

    Seule la requête pour afficher la page d'accueil (c'est-à-dire à la première connexion) sera un GET. Lorsque l'utilisateur cliquera sur le bouton Valider après avoir sélectionné ses produits, une méthode POST sera exécutée.

    C'est cela qui nous permet de différencier le premier affichage des autres, sans avoir à définir plusieurs Servlets.

    On en est là :

    Si tout va bien, ta Servlet doit ressemble à ça :

    ☕ Code Java - StoreServlet
    @WebServlet(name = "storeServlet", urlPatterns = {"/store"})
    public class StoreServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            super.doGet(request, response);
        }
    }
    
  6. Modifier la méthode doGet pour qu'elle redirige vers la vue store.jsp.

Pourquoi avoir un web.xml?

Nous n'avons vu qu'il n'était pas nécessaire de déclarer les Servlets dans le 📄web.xml, on peut se demander si ce fichier est bien utile ...

Oui ! Car il va nous permettre d'ajouter d'autres informations, par exemple, de définir une page par défaut !

Ici par exemple, on souhaiterait pouvoir ne saisir que http://localhost:8080/boutique comme URL, plutôt que http://localhost:8080/boutique/store.

Pour cela, dans le fichier 📄web.xml, il suffit de positionner le code suivant à l'intérieur de la balise <web-app> :

📄web.xml
<welcome-file-list>
    <welcome-file>store</welcome-file>
</welcome-file-list>

Ce welcome-file peut être une page HTML, une page JSP, ou comme ici, une Servlet !

5. Implémentation de la vue⚓︎

Pour l'instant, il n'y a qu'une seule vue. C'est 📄store.jsp. Cette JSP ne contient pour l'instant que du code HTML :

Où placer les JSP ?

Les JSP (ainsi que les pages HTML, le javascript, le CSS, ...) doivent être placées dans le dossier contenu web. Par défaut, c'est le dossier 📂src/main/webapp.

📄store.jsp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Boutique en ligne</title>
</head>
<body>
    <h1>Sélection des produits</h1>
    <form action="store" method="post"><!--(1)!-->
        <fieldset>
            <legend>Liste des produits</legend>
            <table>
                <tr>
                    <td>Stylo</td>
                    <td><input type="number" name="penNb"/>
                    <td></td>
                </tr>
                <tr>
                    <td>Feutre</td>
                    <td><input type="number" name="feltNb"/>
                    <td></td>
                </tr>
                <tr>
                    <td>Gomme</td>
                    <td><input type="number" name="rubberNb"/>
                    <td></td>
                </tr>
            </table>
        </fieldset>
        <input type="submit" value="Valider"/>
    </form>

    <fieldset>
        <legend>Récapitulatif du panier</legend>
        <table>
            <tr>
                <td>Panier :</td>
                <td></td>
            </tr>
            <tr>
                <td>Frais livraison :</td>
                <td></td>
            </tr>
            <tr>
                <td>Prix total :</td>
                <td></td>
            </tr>
        </table>
    </fieldset>
</body>
</html>
  1. Le formulaire HTML (balise <form>) permet à l'utilisateur de saisir des informations, et de les envoyer au serveur en cliquant sur le bouton valider (on dit qu'on "soumet" le formulaire.)

    Toutes les balises <input type="*"> permettent d'envoyer une information au serveur, que nous allons pouvoir récupérer grace à la valeur de l'attribut name.

    La propriété action permet d'indiquer quelle URL va être exécutée à la soumission du formulaire (on fait le lien avec le <url-pattern> dans le 📄web.xml).

    Enfin, la propriété method indique avec quelle méthode la requête HTTP est envoyée. Ici, c'est POST, ce qui nous permettra de différencier le premier affichage de la page (méthode GET), et la soumission du formulaire.