1. Références

2. Mise en place

2.1. Prérequis

Avant de commencer la réalisation de ces travaux pratiques, il est indispensable de disposer des logiciels suivants :

  1. Java Developer Kit, version 8

  2. TomEE, WebProfile 7

  3. Un Atelier de Génie Logiciel professionnel

2.2. Instructions pour Eclipse IDE

2.2.1. Choix de l’espace de travail

Au lancement de l’IDE, il est nécessaire de choisir un emplacement pour l’espace de travail. Cet emplacement sert de racine pour la création de futurs projets.

Choix de l’emplacement de l’espace de travail

2.2.2. Création de projet

Cette étape sera répétée de nombreuses fois par la suite. Il est conseillé de se familiariser avec.
  1. Cliquer sur le menu File  New  Dynamic Web Project…​.

  2. Dans la fenêtre pop-up qui s’ouvre

    • Remplir les champs de la manière suivante :

      Champ Valeur Commentaire

      Project name

      servlet

      Target runtime

      <None>

      Le runtime sera configuré plus tard

      Dynamic Web Module version

      3.0

      Configuration

      Default configuration

      La configuration par défaut comprend Java 8 et l’API Servlet 3.0

      Dynamic Web Project
    • Cliquer sur Next.

  3. L’écran suivant permet de configurer la structure du projet. Conserver les valeurs par défaut et cliquer sur Next.

    Dynamic Web Project - project structure
  4. Dans l’écran suivant :

    • Conserver les valeurs par défaut pour les champs texte.

    • Sélectionner "Generate web.xml deployment descriptor".

    • Cliquer Next.

      Dynamic Web Project - web module
  5. Cliquer Finish.

  6. L’espace de travail doit afficher une structure similaire :

    Projet créé

2.2.3. Configuration du serveur d’applications

  1. Localiser l’onglet "Servers" - par défaut situé en bas. Le sélectionner.

  2. Cliquer sur le lien "No servers are available. Click this link to create a new server…​". Dans le fenêtre qui s’ouvre :

    • Sélectionner l’adapteur Tomcat v 7.0

    • Dans le champ Server name, indiquer "TomEE v1.7 Server at localhost"

      New Server
    • Cliquer Next.

  3. Dans l’écran de configuration de Tomcat :

    • Remplir les champs ainsi :

      Champ Valeur Commentaire

      Name

      TomEE v1.7 Server at localhost

      Tomcat installation directory

      Pointer vers le répertoire d’installation de TomEE à l’aide du bouton Browse

      JRE

      Java SE 8

      Sélectionner un JDK 8 dans la liste déroulante

      New Server - Tomcat Server
    • Puis cliquer Next.

  4. Ajouter le projet précédemment créé en sélectionnant celui-ci puis en cliquant sur le Add.

    New Server - Add and remove

    Puis cliquer sur Finish.

2.2.4. Lancement de l’application

Initialement, le serveur affiche le status [Stopped, Republish].

Publication

La publication consiste à synchroniser les fichiers de configuration et les classes compilées. Cliquer droit et sélectionner Publish.

Lancement

Pour lancer le serveur d’applications, cliquer droit et sélectionner Debug.

L’application est maintenant disponible sous http://localhost:8080/servlet/.

2.3. Instructions pour IntelliJ IDEA

2.3.1. Création de projet

  1. Cliquer sur le menu File  New  Project…​.

  2. Dans la fenêtre pop-up qui s’ouvre:

    • Dans le volet gauche, sélectionner "Web Application"

    • Remplir les champs de la manière suivante :

      Champ Valeur Commentaire

      Project SDK

      1.8

      Utiliser le bouton New pour pointer vers l’installation locale du JDK

      Java EE Version

      Java EE 7

      Application Server

      TomEE 7.0.68

      Le libellé exact dépend de la version installée dans l’étape précédente

      Additional Libraries and Frameworks

      JavaEE Application

      Laisser les valeurs par défaut dans le volet du bas

      New Project - step 1
    • Cliquer sur Next.

  3. Dans la fenêtre suivante :

    • Taper servlet dans le champ Project name

    • Sélectionner un emplacement adéquat pour le champ Project location

      New Project - step 2
    • Cliquer sur Finish.

  4. L’espace de travail doit afficher une structure similaire suivante :

    Project has been created

2.3.2. Configuration du serveur d’applications

  1. Dans IntelliJ IDEA, cliquer sur le menu Run  Edit Configuration :

    Run/Debug Configurations
  2. Tout en haut à gauche, cliquer sur +, puis Defaults  x items more…​  TomEE Server  Local.

    1. Dans la popup, cliquer sur Configure au niveau du champ Application server.

    2. Indiquer l’emplacement du répertoire d’installation de TomEE :

      TomEE Server
    3. Cliquer sur Finish.

  3. Dans le champ Name, indiquer TomEE.

    Run/Debug Configurations
  4. Cliquer sur OK.

2.3.3. Déploiement de l’application

L’étape de création du projet a normalement permis de déployer virtuellement l’application dans le serveur d’applications. De fait, le lancement du serveur déploiera l’application.

2.3.4. Lancement de l’application

  1. Pour construire le projet, cliquer sur Build  Build Project.

  2. Puis, pour lancer l’application, cliquer sur Run  Debug TomEE 7.0.68.

  3. Un navigateur se lance et affiche la page http://localhost:8080/ :

    Browser displaying default page
    Diagnostic

    Si le navigateur affiche une page de type 404 Not Found, appeler l’enseignant/l’assistant.

  4. Avec les connaissances vues en cours, tenter d’expliquer pourquoi cette page est affichée.

3. Manipulation de servlets

Cette section permet de mettre en oeuvre les concepts liés aux servlets étudiés en cours.

3.1. Premiers pas

L’objectif est de créer un servlet qui écrit dans la log système lorsqu’il est accédé en GET.
  1. Créer un nouveau package p.e. ch.hesge.programmation.

    Il est fortement déconseillé de créer des classes dans le package racine.
  2. Créer une nouvelle classe de servlet, SysoutServlet :

    • Hériter de HttpServlet.

    • Implémenter la méthode doGet() : le corps de celle-ci fait un appel à la méthode System.out.println().

  3. Modifier le descripteur de déploiement web.xml pour lier ce servlet au fragment d’URL /sysout.

    Rappel

    Il faut créer une section <servlet> pour lier la classe à un nom logique et une section <servlet-mapping pour lier le nom logique à un modèle d’URL.

  4. Reconstruire l’application et re-démarrer le serveur (cf. ci-dessus).

  5. Accéder à http://localhost:8080/sysout via GET.

  6. Vérifier la sortie de la console dans l’AGL.

3.2. Configuration par annotations

L’objectif est de créer un servlet configuré avec les annotations - et non pas dans le descripteur de déploiement.
  1. Copier-coller la classe ci-dessus en AnnotatedServlet.

  2. Configurer le servlet via les annotations pour qu’il soit accessible en GET via le fragment /annotate.

  3. Accéder à http://localhost:8080/annotate.

  4. Vérifier la sortie de la console dans l’AGL.

3.3. Redirection

L’objectif est de créer un servlet qui redirige l’utilisateur vers un site externe
Via l’API native
  1. Créer une nouvelle classe de servlet, RedirectServlet.

  2. Implémenter la méthode doGet() pour rediriger l’utilisateur vers un site externe, p.e. https://google.com.

  3. Configurer le servlet soit par annotations, soit dans le descripteur de déploiement pour être accessible via /redirect.

  4. Accéder à http://localhost:8080/redirect.

  5. Vérifier que le navigateur redirige vers le site externe précédemment utilisé.

En utilisant un autre mécanisme de bas niveau
  1. Copier-coller la classe ci-dessus en RedirectServlet2.

  2. Remplacer l’implémentation de la méthode doGet():

    • Ajouter le header Location avec l’URL précédente

    • Renvoyer un code statut HTTP de redirection

  3. Configurer le servlet pour être accessible via /redirect2.

  4. Accéder à http://localhost:8080/redirect2.

  5. Vérifier que le navigateur redirige vers le site externe précédemment utilisé.

3.4. Ecriture dans la réponse

L’objectif est de créer un servlet qui écrit directement dans le flux de réponse.
  1. Créer une nouvelle classe de servlet, WriteServlet.

  2. Implémenter la méthode doGet() pour écrire du contenu HTML dans le flux de réponse en utilisant response.getWriter().

    Ne pas oublier
    • De fermer le flux de sortie, sinon la page ne sera pas affichée

    • D’indiquer le type MIME afin que le contenu HTML soit correctement interprété et non pas affiché comme du simple texte. Pour information, la plupart des navigateurs "sniffent" le type mais il s’agit d’une faille de sécurité.

  3. Configurer le servlet pour être accessible via /write.

  4. Accéder à http://localhost:8080/write.

  5. Vérifier que le navigateur affiche correctement le contenu HTML.

3.5. Utilisation des paramètres

L’objectif est de lire et d’afficher les paramètres de requête.
  1. Créer un servlet, ParamServlet.

  2. Configurer le servlet pour être accessible via /param.

  3. Ecrire dans le flux de réponse les paramètres sous forme de tableau HTML :

  4. Vérifier l’affichage des résultats avec les URL suivantes :

3.6. Forward

L’objectif est de créer un servlet qui forward vers une autre ressource.
  1. Créer deux servlets, InitialServlet et ForwardServlet.

  2. Les configurer pour être respectivement accessibles via /initial et /forward.

  3. Dans le premier servlet, implémenter le forward vers le second.

  4. Dans le second servlet, écrire quelque chose dans le flux de réponse.

  5. Accéder à http://localhost:8080/initial.

  6. Vérifier que le navigateur affiche ce qui a été écrit dans ForwardServlet.

3.7. Inclusion

L’objectif est de créer un servlet qui inclut une autre ressource.
  1. Créer deux servlets, InitialServlet2 et IncludeServlet.

  2. Les configurer pour être respectivement accessibles via /initial2 et /include.

  3. Dans le premier servlet, implémenter :

    • une écriture dans le flux de réponse

    • l'include vers le second servlet

    • une seconde écriture dans le flux de réponse

  4. Dans le second servlet, écrire quelque chose dans le flux de réponse.

  5. Accéder à http://localhost:8080/initial2.

  6. Vérifier que le navigateur affiche ce qui a été écrit dans le flux de réponse dans le bon ordre.

4. Manipulation de JSP

4.1. Premiers pas

L’objectif est d’afficher une page HTML.
  1. Créer un fichier HTML hello.html dans le répertoire racine de l’application web.

  2. Accéder à http://localhost:8080/hello.html.

  3. Vérifier que le navigateur affiche le contenu.

4.2. Contenu statique

L’objectif est d’afficher le contenu statique d’une JSP.
  1. Créer une page JSP hello.jsp avec un contenu statique dans le répertoire racine de l’application web.

  2. Accéder à http://localhost:8080/hello.jsp.

  3. Vérifier que le navigateur affiche le contenu statique.

4.3. Contenu dynamique

L’objectif est d’afficher le contenu dynamique d’une JSP.
  1. Créer une JSP date.jsp avec un contenu dynamique dans le répertoire racine de l’application web. Par exemple, afficher l’instant présent <%= new Date() %>.

  2. Accéder à http://localhost:8080/date.jsp.

  3. Vérifier que le navigateur affiche le contenu dynamique en rafraichissant plusieurs fois la page.

4.4. Implémentation du modèle MVC

L’objectif est d’implémenter le modèle MVC avec un servlet frontal qui joue le rôle de contrôleur et une JSP qui joue le rôle de la vue.
  1. Créer un servlet DateServlet qui génère la date comme dans la section précédente.

  2. Implémenter un forward vers la JSP.

  3. Le rendre accessible via /date.

  4. Créer une JSP date2.jsp dans le répertoire racine de l’application web.

  5. Faire en sorte que la JSP récupère la date générée par le servlet et l’affiche.

  6. Accéder à http://localhost:8080/date.

  7. Vérifier que la date est bien affichée.

  8. Accéder à http://localhost:8080/date2.jsp.

  9. Que se passe-t’il ? Pourquoi ?

4.5. Protection de JSP

Corriger la solution précédente pour que la JSP ne soit pas accessible directement via http://localhost:8080/date2.jsp.

4.6. Exemple complet

Reprendre l’exercice d’affichage des paramètres et l’implémenter avec le modèle MVC.

5. Manipulation de filtres

5.1. Filtre de post-processing

L’objectif est d’implémenter un filtre qui formate une classe de modèle.

Soit les classes suivantes :

Person.java
public class Person {

    public final String firstName;
    public final String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
PersonServlet.java
@WebServlet("/person/*")
public class PersonServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res) {
        String firstName = req.getParameter("firstName");
        String lastName = req.getParameter("lastName");
        Person person = new Person(firstName, lastName);
        req.setAttribute("person", person);
    }
}

Le modèle doit être formaté en fonction du type demandé. Celui-ci est passé dans le chemin d’URL p.e. /person/xml. Les données sont passées en paramètre de requête. Voici un échantillon de requêtes et les réponses attendues :

Requête Réponse

http://localhost:8080/person/xml?firstName=John&lastName=Doe

<person>
  <firstName>John</firstName>
  <lastName>Doe</lastName>
</person>

http://localhost:8080/person/json?firstName=John&lastName=Doe

{
  "person": {
    "firstName": John,
    "lastName": Doe
  }
}

http://localhost:8080/person/html?firstName=John&lastName=Doe

Person

First Name: John
Last Name: Doe
  1. A l’aide d’une combinaison des classes fournies, de filtres et de JSP, implémenter la logique ci-dessus.

  2. Il existe un grand nombre de combinatoires possibles. Déterminer la meilleure architecture.

  3. Justifier le choix.

Les classes fournies ne doivent pas être modifiées.

5.2. Filtre d’authentification

L’objectif est d’implémenter un filtre qui permet de vérifier si l’utilisateur est authentifié.

Le diagramme suivant indique le flux à implémenter:

authenticate filter

Les composants sont :

Composant Type Responsabilité

AuthenticationFilter

Filtre

Vérifie si la session utilisateur comporte l’attribut d’authentification

MainPage

JSP

Affiche la page de bienvenue dans l’application

AuthenticationPage

JSP

Affiche la page d’accès refusé, qui comprend un formulaire d’authentification

AuthenticationServlet

Servlet

Stocke l’attribut d’authentification dans la session utilisateur

6. Gestion de la sécurité

Remplacer l’implémentation précédente par le mécanisme de sécurisation des URL vu en cours.

7. Manipulation d’abonnés au cycle de vie

7.1. Abonnement au cycle de vie des objets de session

L’objectif est d’écrire dans la sortie système lorsqu’un objet est stocké dans une session utilisateur.
  1. Créer un abonné du type adéquat

  2. Enregistrer l’abonné

  3. Quand un objet est stocké, l’abonné doit écrire le nom de l’attribut et l’objet dans la sortie système. Si l’objet est multi-valué (tableau ou liste), écrire chacun des éléments qui le compose.

  4. Créer un composant de test qui permet de stocker 1 à n objets dans la session sous une clé générique

  5. Tester le bon fonctionnement du composant avec les valeurs suivantes :

    Clé Valeur

    "objet"

    new Object()

    "date"

    new java.util.Date()

    "array"

    { new Object(), new Object(), new java.util.Date() }

    "list"

    Arrays.asList(new Object(), new Object(), new java.util.Date())

7.2. Abonnement au cycle de vie des sessions

L’objectif est d’offrir un service qui donne retourne le nombre de sessions utilisateur existantes à un instant t.
  1. Créer un abonné du type adéquat

  2. Enregistrer l’abonné

  3. Choisir le bon contexte pour stocker le nombre de sessions

  4. Lorsqu’une session est créée, incrémenter le compteur de sessions. Lorsqu’elle est détruite, décrémenter le compteur

  5. Créer un composant pour afficher le compteur à l’utilisateur

Une session est créée lorsque la méthode HttpServletRequest.getSession() est appelée. Cette méthode est appelée implicitement lors d’un forward/include de JSP.

8. Gestion des erreurs

8.1. Page Not Found

  1. Créer une page d’erreur dédiée de type Page Not Found

  2. Configurer l’application pour que les erreurs 404 soient redirigées vers cette page

  3. Tester

8.2. Erreurs serveur

  1. Créer une page d’erreur dédiée de type Internal Server Error

  2. Configurer l’application pour que les exceptions non interceptées soient redirigées vers cette page

  3. Tester (avec un servlet qui lance une exception)

9. Internationalisation de JSP

9.1. Externalisation des libellés

L’objectif est de migrer l’intégralité des libellés d’une page JSP dans un fichier spécifique.

Soit la JSP suivante :

person.jsp
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Création de Personne</title>
</head>
<body>
<h1>Création de Personne</h1>
<form>
    <label for="firstName">Prénom :</label>
    <input type="text" id="firstName" name="firstName"/>
    <label for="lastName">Nom :</label>
    <input type="text" id="lastName" name="lastName">
    <input type="submit" value="Enregistrer">
</form>
</body>
</html>

A l’aide des techniques d’internationalisation vues en cours, externaliser l’intégralité des libellés de la JSP dans un fichier de properties.

9.2. Internationalisation d’application

L’objectif est d’afficher la page JSP précédente en fonction de la locale du navigateur.
  1. En plus du fichier racine précédent, créer au moins deux fichiers de properties pour des locales différentes (mais sans relation de parenté entre elles).

  2. Créer un servlet qui va lire la locale du navigateur

    Il est possible de changer la locale de Chrome en allant dans chrome://settings/languages. Pour les autres navigateurs, se référer à leur documentation respective.

  3. Passer la locale à la JSP

  4. Afficher la JSP avec les libellés qui correspondent à la locale