Création d'un blog avec Web Services + client Ajax

De $1

Version de 09:07, 18 Avr 2024

cette version.

Revenir à liste des archives.

Voir la version actuelle

Introduction

Dans ce TP nous allons partir d'un projet existant, le faire tourner, et l'améliorer. Il s'agit d'un petit projet simulant un blog. Nous allons commencer par créer le projet, créer une classe entité représentant les articles du blog, ajouter des web services permettant de manipuler ces données via des URIs, et enfin développer un client en HTML + JavaScript utilisant la bibliothèque jQuery pour la manipulation du DOM et pour les requêtes Ajax.

Création du projet, d'une classe entité Article, et d'un session bean façade

  1. Créez un projet de type web.
     
  2. Créez à l'aide du gestionnaire de base de données de Netbeans une base de données intitulée "blogWS" avec comme login/password admin/admin.
     
  3. Ajoutez au projet une classe entité Article, vous indiquerez au gestionnaire de persistence qu'il travaille sur une nouvelle source de données et indiquerez comme source de données celle que vous venez de créer. Autorisez le drop and create pour le moment, car nous risquons de modifier le modèle de données.
     
  4. Vous mettrez comme propriétés dans la classe Article au moins le titre de l'article, son contenu et la date à laquelle il a été posté. Rappel : une propriété est un attribut avec des getters/setters.
     
  5. Rajoutez deux constructeurs : un vide et un prenant en paramètre un titre et un contenu. Dans le constructeur vous initialiserez la date avec dateCreation = new Date() par exemple.
     
  6. Maintenant, vous allez ajouter une couche de DAO sous la forme d'un session bean stateless permettant de gérer des Articles (faire le CRUD) et exposant ses méthodes sous la forme de Web Services REST. Pour cela nous allons utiliser un wizard bien pratique de Netbeans. Faire clic droit/new/RESTful Web Services for entity classes et indiquez la classe Article comme entité. Je vous conseille d'indiquer comme package pour cette classe DAO/WS un nom comme "api" ou "services". Regardez le code généré, vous avez une classe ArticleFacadeREST qui hérite de AbstractFacade.
     
  7. Etudiez le code de ces deux classes, remarquez que le session bean stateless (il y a bien @Stateless avant la délclaration de la classe) est annoté de "chemin" (@Path) devant le nom de la classe et devant les noms des méthodes. Je vous conseille, pour des raisons pratiques, de modifier le premier chemin dans l'annotation @Path juste en dessous de @Stateless pour mettre quelque chose de plus parlant, par exemple @Path("articles")

Nous devrons par la suite certainement améliorer/modifier/ajouter des choses dans cette classe (de nouveaux Web Services par exemple, accepter de nouveaux formats d'entrée ou de sortie, etc.).

Création d'un petit client pour ajouter des données dans la base via un web service.

Dans la page index.jsp ou index.html, nous allons ajouter un formulaire permettant d'ajouter des articles. Mettez donc un formulaire de ce type :

<form method="post" enctype="application/x-www-form-urlencoded" action="resources/articles">
            <p>
                <label for="titre">Titre</label>
                <input type="text" name="titre"/>
            </p>
            <p>
                <label for="content">Texte</label>
                <textarea id="content" name="contenu"></textarea>
            </p>

            <p>
                <input name="soumettre" type="submit">
            </p>
</form>

Ce formulaire va nous permettre de remplir la base de données sans trop se fatiguer. Il va falloir néanmoins ajouter un web service indiquant que l'on va travailler avec en entrée le type de données provenant d'un formulaire HTTP. Ce type n'est ni XML ni JSON...

Notez que le formulaire fait un POST (action="POST"), ce qui dans le vocabulaire REST signifie "insère dans la collection des Articles" un nouvel article, puisque l'URI de la collection sur laquelle on pointe ("resources/articles") est bien "articles". Voir le cours.

 Snap2.jpg

Ajoutez donc dans le fichier .java de vos Web Services un truc qui ressemble à cela :

@POST
    @Consumes({MediaType.APPLICATION_FORM_URLENCODED})
    public Response createFromFormulaire(@FormParam("titre") String titre,
                                         @FormParam("contenu") String contenu) {
        Article a = new Article(titre, contenu);
        super.create(a);

        // Create URI for Response  
        UriBuilder b = uriInfo.getBaseUriBuilder();
        URI u = null;
        try {
            u = new URI(b.path(ArticleFacadeREST.class).build() + "/" + a.getId());
            System.out.println("Donnée créée avec comme URI : " + u);
            System.out.println("Dans create titre: " + a.getTitre() + " content: " + a.getContenu());

        } catch (URISyntaxException ex) {
            Logger.getLogger(ArticleFacadeREST.class.getName()).log(Level.SEVERE, null, ex);
        }
        return Response.created(u).build();
    }

Rajoutez également comme attribut de cette classe une variable de type UriInfo, annotée par @Context. Cette variable nous permettra dans le code de connaitre l'URI du web service invoqué.

@Context
 UriInfo uriInfo;

Dans le fichier ApplicationConfig.java, changez le chemin "de base" d'accès à vos web services :

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package service;

import java.util.Set;
import javax.ws.rs.core.Application;

/**
 *
 * @author tirius
 */
// MICHEL BUFFA : changer la ligne ci-dessous !
@javax.ws.rs.ApplicationPath("resources")
public class ApplicationConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
        // following code can be used to customize Jersey 2.0 JSON provider:
        try {
            Class jsonProvider = Class.forName("org.glassfish.jersey.jackson.JacksonFeature");
            // Class jsonProvider = Class.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");
            // Class jsonProvider = Class.forName("org.glassfish.jersey.jettison.JettisonFeature");
            resources.add(jsonProvider);
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        addRestResourceClasses(resources);
        return resources;
    }

    /**
     * Do not modify addRestResourceClasses() method.
     * It is automatically re-generated by NetBeans REST support to populate
     * given list with all resources defined in the project.
     */
    private void addRestResourceClasses(Set<Class<?>> resources) {
        resources.add(service.ArticleFacadeREST.class);
    }
    
}

Quelques remarques :

  1. Ce web service est appelé par un @POST, il est néanmoins différent de celui qui avait été généré (que l'on n'a pas modifié, il est toujours là).
  2. Il renvoie un objet de type Response (ce qui est dans la RFC). Nous verrons que dans cet objet on mettra l'URI de la donnée créée.
  3. Il accepte en entrée un formulaire encodé. Pour celà on utilise MediaType.APPLICATION_FORM_URLENCODED qui est une constante fournie par la librairie Jersey. Elle correspond au "application/x-www-form-urlencoded" du formulaire.
  4. On construit l'URI de la donnée crée à l'aide des classes URIinfo, URIBuilder et URI, et on met l'URI créé dans la réponse (dernière ligne).

Exécutez votre application, utilisez le formulaire pour créer des articles, regardez à l'aide de Firebug ou équivalent la réponse envoyée chaque fois que l'on soumet le formulaire. Vous devriez avoir Location: suivi de l'URI de la donnée ajoutée.

 Snap1.jpg

Avant d'aller plus loin, nous allons tester rapidement les autres web services, maintenant que nous avons des données...

Test de vos Web Services

Nous allons maintenant rapidement tester les Web Services. Pour cela il faut créer un second projet de test, de type web application.

Créez donc un second projet appelé testBlogWS, de type web. Ne mettez rien dedans.

Revenez sur le premier projet, celui du blog et faites clic droit/testRestFul Web Services. Une fenêtre de dialogue apparait, proposant de générer un client de test pour vos web services. Ne prenez pas la première option, mais la seconde, qui vous demande de choisir parmis les projets, celui dans lequel le client de test va être généré. Choisissez le projet testBlogWS. Cliquez sur ok, attendez un peu...

Normalement une fenêtre permettant de tester vos web services va apparaitre. Essayez de lister les données que vous avez créées dans la section précédente.

Implémentation d'un blog à l'aide d'appels AJAX

Nous allons utiliser la librairie jQuery pour ajouter/modifier/supprimer/mettre à jour les données que nous avons créées. Je vous propose de récupérer dans son intégralité un TP que m'a rendu un étudiant de M2 Miage. Tout n'est pas parfait dans ce code (notamment, la manière dont les web services renvoient des réponses).

Snap3.jpg

Récupérez le projet, dézippez le, ouvrez-le dans netbeans, regardez le fichier de configuration de la base de données utilisée (glassfish-resources.xml), créez la base, lancez le projet, étudiez-le !

Comparez les classes Article.java, les web services que vous avez écrits dans votre projet, etc. avec ceux de ce projet.

Regardez les fichiers index.html et function.js où se passent tous les appels Ajax vers les WebServices. Le fichier function.js utilise massivement la librairie JavaScript jQuery qui fournit des sélecteurs pour manipuler le DOM vraiment très pratiques. jQuery permet également d'utiliser les quatre ordres HTTP pour parler à des web services, tout en précisant les types de données envoyées et acceptées en retour.

Pour ceux qui ne connaissent pas jQuery

Si vous ne connaissez pas Ajax et jQuery, allez faire un tour sur la page de ressources jQuery que j'ai réalisée :Ressources JQuery. Voir aussi pour de nombreux tutoriaux interactifs sur jQuery : http://www.w3schools.com/jquery/default.asp les sections "jquery selectors" et "ajax".

Je fais un TP en M1 sur jQuery : TP jQuery, support de cours recommandé pour débuter : http://ejohn.org/apps/workshop/intro/