ClientHTML5

De $1

Version de 17:30, 2 Mai 2024

cette version.

Revenir à liste des archives.

Voir la version actuelle

Dans cette section du TP, nous allons créer un client HTML5 qui consumera le web service.  Ce TP se basera fortement sur le cours HTML5 que vous avez eu avec Michel Buffa cette année.  Nous utiliserons aussi  knockout, une bibliotheque JavaScript  qui nous permettra de faire du MVVM en utilisant que du JavaScript et les métadonnées MTML5.

Knockout

Knokcout  est une librairie Javascript Open Source permettant de faire du MVVM (Model Vue Vue Model). Le pattern MVVM permet une communication bidirectionnel entre le model et la vue sans passer par un contrôler ; Il est particulièrement intéressant pour les vues dynamiques. L’idée est d’associer les contrôles d’une vue avec des attributs d’un modèle de telle sorte que les modifications de l’un soient automatiquement prises en compte par l’autre.

Afin de vous aider à mieux comprendre le principe des services web, nous allons créer une autre application web complètement séparée de l'application Web exposant le Web Service. 

  • Créez un projet HTML5/JavaScript sur Netbeans (File à New Project à HTML5 javaScript è Next)

 

 html5-screen_1.png

  •  Dans la fenêtre suivante, nommez votre projet puis Next  

 html5-screen_2.png

  • Sur la prochaine interface, choisissez l’option Download Online Templates è Twitter Bootstrap è Next

    html5-screen_3.png 
  • Dans l’écran qui suit, sélectionnez Jquery et Knockout en appuyant à chaque fois sur > pour les faire passer du panel de gauche vers celui de droite è Finish

    html5-screen_4.png
  • A ce niveau vous devez avoir un projet qui ressemble à ceci

    html5-screen_5.png  
  • Ajoutez une nouvelle page html au projet (Faites bouton doigt sur le projet è  New è  HTML File)
  • Ajoutez les références jquery et knockout à la page que vous venez de créer  

N.B : Avec Jquery, on peut lancer déclencher automatiquement une action au chargement de la page, indépendemment de l'action utilisateur. Nous allons utiliser cette option pour lancer une requête AJAX au service Web.

$(function() {
                $.ajax({
                    url: "http://localhost:8080/Bibliotheque/webresources/categorie",
                    type : "GET",
                    headers: {
                        Accept: "application/json"
                    }
                })
                        .success(function(data, status, jq) {
                    $("div").text(JSON.stringify(data));
                })
                        .error(function(jq, status, error) {
                    $("div").text(JSON.stringify(status + " " + error));
                    
                });

            });
  •  Exécutez le projet (Faites bouton doigt sur le projet puis Run)

Normalement, la requête ne doit pas aboutir! Elle est due au fait que votre application web et l'application RESTFull sont sous des domaines différents (localhost:8080 et localhost:8383).  C'est un mécanisme de sécurité sur les serveurs applicables aux requetes AJAX.  Elle est liée au Cross domain du serveur qui filtre les requetes AJAX en provenance d'un autre domaine. L'une des façons de palier ce problème est de modifier les paramètres du serveur pour accepter les requête asynchrones tout autre ou pour certains domaines en fonction des besoins de l'application;  Dans notre cas, nous allons modifier la configuration de notre application RESTFull pour acceter des requetes de n'importe quel domaine. 

  1. Créer une classe RequestFilter dans votre application RESTFull qui se chargera de filtrer toutes les requetes vers le service qui dans JERSEY sont gérées par la servlet javax.servlet.Filter
  2. Faites hériter votre classe de javax.servlet.Filter
  3. Votre classe doit ressembler à ceci 
@WebFilter(filterName="Test",urlPatterns={"/webresources/*"})
public class Test implements javax.servlet.Filter{
 
 @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("doFilter");
        HttpServletResponse res = (HttpServletResponse) response;
        //Dire qu'on accepte des requetes de n'importe quel domaine sur les ressources gérés par la servlet
        res.addHeader("Access-Control-Allow-Origin", "*");
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Init");
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }


    @Override
    public void destroy() {
        System.out.println("destroy");
       // throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

Nous allons maintenant utiliser knockout pour afficher la réponse dans un tableau

  • Créer un modèle pour représenter la/les ressources utilisées dans la vue  

Note : knockout propose la méthode observable, qui permet de s'abonner aux modifications qui pourront s'effectuer sur un objet. Dire qu'un objet est observable signifie que tout changement effectué sur l'objet est pris en compte par la vue associée et reciproquement.

var Category = function(categorie) {
                this.id = ko.observable(categorie.id);
                this.nom = ko.observable(categorie.nom);
                this.description = ko.observable(categorie.description);
            };
  • Créez un modèle pour la vue

Note: Le modèle ici représente la logique applicative de la vue (liste des categories, ajouter/editer/supprimer categorie etc....)

var ViewModel = function(categories) {
                var self = this;
		//représente la liste des catégories
		//La fonction prend la réponse obtenue du serveur en paramètre
		//Ici nous supposons que vous avez chargé la liste des catégories
		//ko.utils.arrayMap itère sur la collection et pour chaque objet trouvé, elle crée une instance de categorie 
                self.categories = ko.observableArray(ko.utils.arrayMap(categories, function(categorie) { return new Category(categorie);}));
                };
  • Créons une table html pour afficher la liste des catégories! Remplacez la balise div par le contenu suivant :
<h2>Categories</h2>
        <div class='categorielist'>
            <table class='contactsEditor'>
                <tr>
                    <th>Id</th>
                    <th>Nom</th>
                    <th>déscription</th>
                </tr>
                <tbody data-bind="foreach: categories">
                    <tr>
                        <td>
                            <label data-bind='text: id' ></label>
                        </td>
                         <td>
                            <label data-bind='text: nom' ></label>
                        </td>
                         <td>
                            <label data-bind='text: description' ></label>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
        <div class="error"></div>

Note : Dans ce code, nous avons ajouté un table à trois colonnes (Id, Nom, Description)
Observez bien le contenu de la balise tbody, avez vous remarqué l'attribut "data-bind", knockout l'utilise pour faire du databinding sur les composants d'une vue. la fonction foreach permet d'itérer sur l'attribut categories du modèle de la vue. Pour chaque objet catégorie trouvé, une ligne sera ajouté dans la table avec en colonne les valeurs des attributs de l'objet courant.

  • Modifie la requete ajax pour créer le modèle de la vue quand une réponse est reçue du serveur. La requête AJAX devient :
$(function() {
                $.ajax({
                    url: "http://localhost:8080/Bibliotheque/webresources/categorie",
                    type: "GET",
                    headers: {
                        Accept: "application/json"
                    }
                })
                        .success(function(data, status, jq) {
                    ko.applyBindings(new ViewModel(data));
                })
                        .error(function(jq, status, error) {
                    $(".error").text(JSON.stringify(status + " " + error));

                });

            });
  •  Testez la page! Normalement vous devriez avoir quelque chose comme ça : 

result8html5_1.png

  • Mettez un peu de style sur la page
<style>
            body { font-family: arial; font-size: 14px; }

.categorielist { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.categorielist input { font-family: Arial; }
.categorielist b { font-weight: bold; }
.categorielist p { margin-top: 0.9em; margin-bottom: 0.9em; }
.categorielist select[multiple] { width: 100%; height: 8em; }
.categorielist h2 { margin-top: 0.4em; font-weight: bold; font-size: 1.2em; }
.error { color: red; }
.categorielist TR { vertical-align: top; }
.categorielist TABLE, .categorielist TD, .categorielist TH { padding: 0.2em; border-width: 1px; margin: 0; }
.categorielist TD A { font-size: 0.8em; text-decoration: none; }
.categorielist table.contactsEditor > tbody > TR { border-bottom: 1px solid silver; }
.categorielist td input { width: 8em; }
        </style>

Jouons un peu avec knockout!

  • A la place d'un label dans les champs du tableeu, mettez un input
<table class='contactsEditor'>
                <tr>
                    <th>Id</th>
                    <th>Nom</th>
                    <th>déscription</th>
                </tr>
                <tbody data-bind="foreach: categories">
                    <tr>
                        <td>
                            <label data-bind='text: id' > </label>
                        </td>
                        <td>
                            <input data-bind='value: nom' />
                        </td>
                         <td >
                            <input data-bind='value: description' />
                        </td>
                    </tr>
                </tbody>
            </table>
  • Testez maintenant!

result8html5_2.png

  • Inventons cette règle pour le fun! Nous autoriserons l'édition d'une ligne uniquement si l'id est pair!
<input data-bind='value: description, enable: (parseInt(id())%2 ===0)' />

result8html5_3.png

Voyez ce qui se passe quand vous faites des modifications sur la vue!
  • Ajoutez une nouvelle colonne action dans la table, afin d'ajouter des composantes pour effectuer des actions sur le modèle.
  • Pour chaque ligne du tableau ajoutez un bouton suppression et un bouton mise à jour!
  • Ajoutez deux nouvelles fonctions pour la suppression et la mise à jour d'une catégorie

Note : La suppression se fait dans la liste des contacts

A ajouter dans la vue

<input type="button" value="Supprimer" />

A ajouter dans le modèle

self.remove = function(categorie){
                   self.categories.remove(categorie);
                    $.ajax({
                        url: "http://localhost:8080/Bibliotheque/webresources/categorie/" + categorie.id(),
                        type: "DELETE",
                        contentType: "application/json",
                        headers: {
                        Accept : "application/json"
                    }
                    })
                            .success(function(data, status, jq) {
                        // alert(status);
                        self.categories.remove(categorie);
                    })
                            .error(function(jq, status, error) {
                        $(".error").text(JSON.stringify(status + " " + error));

                    });
                };
                self.update = function(categorie){ 
                   //Effectuez votre requête AJAX ici
                };