ENSEEIHT Rapport de Projet d'application pour l'internet Site de location de matériel et d'édition de devis Bastien BARTHET, Adrien CHAMPION, Benoit ESTEVENON, Thibaut ETIENNE, Bastien LEHMANN Juin 2009
1 Sommaire 2 Introduction... 3 3 Cahier des charges du client... 3 4 Technologies employées... 3 5 Côté serveur... 4 5.1 Modèle entité de la base de données... 4 5.2 Beans... 5 6 Sécurité et authentification... 5 7 Côté client... 5 7.1 L architecture du site... 5 7.2 AJAX... 6 7.2.1 Ajax.Request... 6 7.2.2 Ajax.Updater... 7 7.2.3 D autres façons de gérer les requêtes... 7 7.2.4 Les effets graphiques... 7 7.3 Servlet et JSP... 8 7.3.1 Création d un client... 8 7.3.2 Identification d un client... 8 7.3.3 Edition d un profil client... 9 8 Génération de devis et facture en PDF... 10 8.1 Pourquoi?... 10 8.2 Intégration générale à l architecture du site... 10 8.3 Outils utilisés pour la génération... 10 9 Répartition du travail... 10 10 Problèmes rencontrés... 11 10.1 Castage d'arraylist... 11 10.2 Internet Explorer vs Firefox... 11 10.3 Adressage relatif des fichiers PDF généré... 11 11 Conclusion... 12 2
2 Introduction Après avoir étudié plusieurs technologies web en cours, le présent projet a pour objectif de les mettre en application sous la forme d un site web. Le thème de ce dernier n est pas imposé, mais il doit être du type e-commerce. C'est-à-dire qu il doit proposer la vente ou location de différents objets. 3 Cahier des charges du client Ici, il s agira d un site de location en ligne de matériel d une association de technique de spectacle (Son&Lumière). Il s agit d un élément primordial. En effet, c est lui qui va aiguiller le développement du site. Il vise à définir exhaustivement les spécifications de base du site à réaliser. La demande est de pouvoir parcourir le parc de matériel, d'en faire un panier à la manière d'un quelconque site de e-commerce, et enfin de pouvoir éditer les devis, facture et bon de livraison. Le stockage de toutes les commandes passées doit être également assuré. Deux types d'utilisateurs sont prévus quant à l'utilisation du site : les clients. Ils peuvent consulter les produits, constituer un panier, voir leurs commandes passées ou en cours, et éditer leur devis et ainsi que leur profil. l'administrateur. Il peut modifier la base de données des produits, modifier n'importe quelle commande, et visualiser les clients. Il est le seul à pouvoir éditer une facture ou un bon de livraison. 4 Technologies employées Le but des technologies employées est de bien séparer le modèle, la vue et le contrôleur (MVC). Ainsi il est aisé de travailler sur chaque parti indépendamment. De plus, la modularité ainsi apportée permet de répartir facilement les différentes tâches entre les différents membres du groupe. Le côté serveur, ou Back End, est écrit en EJB3 simplifiant ainsi la gestion des entités de la base de 3
données et la communication avec les clients. Des Servlets de manipulation des EJB sont déployés côté client pour chaque action potentiellement effectuée par le client. L'interface utilisateur se présente sous forme de pages HTML intégrant du JavaScript, de l'ajax, du CSS et interaction avec les Servlets via des JSP. 5 Côté serveur 5.1 Modèle entité de la base de données Adresse Client CommandeValidee int id String ville String rue int codepostale 1 1 String login String role int reduction String password String beneficiaire String email String tel Adresse adr Collection<Commande> Collection<CommandeValidee> 1 N 1 int id String nom String cheminversimage String cheminversfacture String cheminversbondelivraison N Produit Int id String name String description int quantite Float prix String cheminversimage String categorie ProduitQuantite 1 Int id N 1 Produit p int quantite Commande int id String titrecommande Date datesortiemateriel Date dateretourmateriel Collection<ProduitQuantite> Voici le schéma Entité-relation de la base de données déployée. Chaque client possède des commandes. Chaque commande possède des produits sous la forme de couple (produit, quantité), regroupé dans le type ProduitQuantité, pointant sur la base de données des produits. Une fois une commande validée, l'objet Commande est supprimé et est remplacé par un objet CommandeValidee, de façon à ne plus évoluer avec la BD. En effet si l'administrateur modifie le prix d'un produit dans la BD, toutes les commandes en cours utilisant ce produit se verront modifiées (aucun prix total n'est stocké, mais uniquement les prix unitaires et les quantités). Afin de mieux distinguer les produits d'une catégorie ou d'une sous-catégorie, et de pouvoir lister une commande par catégorie, des structures plus complexes de stockage furent envisagées, comme définir des types génériques ou des HashMap. Le choix d une liste ordonnée c est finalement imposé pour représenter les produits d'une commande. La fonction d'ajout regroupe le nouveau produit 4
avec ceux de sa catégorie/sous-catégorie, afin de pouvoir ensuite lister les produits de façon plus claire sur les devis. 5.2 Beans Pour manipuler ces entités, 3 classes de type SessionBeans ont été déployées pour gérer respectivement les Produits, les Commandes et les Clients. Chacun fourni au client les fonctions nécessaires à l'utilisation, en restreignant ainsi les risques de mauvaise utilisation. 6 Sécurité et authentification Le problème de l'authentification des clients et de l'identification du rôle de celui-ci (administrateur ou simple client) a été géré par l'ajout de la clé client à la session. La session, de type HttpSession, permet de faire persister des informations tout au long d'une connexion, jusqu'à un time-out ou un retrait des informations. Tout ceci est géré par les servlets. Le client rentre donc son login et mot de passe, qui sont ensuite contrôlé coté Beans, puis en cas de bonne identification le serveur renvoi au client son rôle, qui est inscrit dans la session avec la clé client. Ce contrôle se passe donc côté Servlet et permet ainsi à chaque action du client de savoir, d'une part si il est bien authentifié et autorisé à appeler la méthode qu'il appelle, et d'autre part à connaître l'identité du client à chaque instant. 7 Côté client 7.1 L architecture du site Notre site ne dispose vraiment que de trois pages: la page d'accueil la page client (une fois ceux-ci loggés) la page administrateur (une fois celui-ci loggé) A l'intérieur de ces pages, toutes les actualisations se font par mise à jour par fragment à l'aide d'ajax et en particulier de la librairie prototype.js (http://www.prototypejs.org/). Deux objets sont principalement utilisés, Ajax.Request et Ajax.Updater. 5
7.2 AJAX 7.2.1 Ajax.Request Voici un exemple d'utilisation d'ajax.request : 6
function admingetclients() { var date = new Date(); var param = "dummy=" + date; new Ajax.Request('ActionListerClient', { method : 'post', parameters : param, oncomplete : function(response) { $('maindisplay').innerhtml = response.responsetext; ); Ajax.Request est adapté aux appels à une servlet. Une fois la requête terminée, l'action définie dans le champ oncomplete est exécutée, ici on actualise le fragment central avec la liste des clients (renvoyée sous forme d'une JSP par la servlet appelée). 7.2.2 Ajax.Updater Voici un exemple d'utilisation d'ajax.updater: function ajaxupdater(container, url) { new Ajax.Updater(container, url); Nous utilisons exclusivement Ajax.Updater pour des appels directs aux JSPs sans passer par une servlet. La fonction considérée ici permet de mettre à jour un fragment (typiquement un div) dont l'id est «container» avec la JSP à l'adresse «url». 7.2.3 D autres façons de gérer les requêtes Prototype.js est compatible avec le standard JSON (http://www.prototypejs.org/learn/json) qui, pour ce que nous en avons lu, semble présenter des avantages certains et est fortement recommandé par les «gros bonnets» du domaine. Cependant, à cause du nombre conséquent de projets en simultané et de l'approche des partiels nous avons préféré nous en tenir à des technologies plus facilement abordables. A noter également que prototype.js gère également les formats couramment employés pour la création de pages ou de fragments dynamiques tels que XML et DOM. 7.2.4 Les effets graphiques Pour étoffer l'aspect visuel du site, nous avons tout d'abord commencé à nous pencher sur plusieurs librairies isolées telles que Rico (http://openrico.org/), ainsi que sur des scripts spécialisés (comme on peut en trouver ici : http://www.miniajax.com/). Rapidement sont apparus de gros problèmes de compatibilité entre les librairies et les scripts par rapport aux noms de variables, aux noms de fonctions, ainsi qu'au CSS pour les scripts spécialisés. De plus, les librairies telles que Rico fournissent des effets de trop haut niveau assez peu modifiables à moins de modifier le code source, chose que nous n'avions pas le temps de faire. Il a donc été décidé d'utiliser scriptaculous (http://script.aculo.us/) qui donne accès à des effets assez simples mais plutôt efficaces et surtout plus facilement adaptables au cas par cas. 7
Les effets principalement utilisés sont Effect.BlindUp, Effect.BlindDown, Effect.Appear, Effect.Fold... (http://wiki.github.com/madrobby/scriptaculous). En particulier, il a été défini une petite fonction très pratique: // Fonction d'apparition et de disparition function slidethat (that) { var dis = document.getelementbyid(that); var state = dis.getattribute("class"); if (state == "on") { Effect.BlindUp(that); dis.setattribute("class", "off"); else { Effect.BlindDown(that); dis.setattribute("class", "on"); Elle permet de faire apparaître ou disparaître un fragment (un div) très facilement. Cependant elle n'est pas très propre et pose un problème : dans la mesure où la classe du fragment est utilisée pour savoir s'il est visible ou non, deux clics trop rapprochés rendront incohérent l'état de classe si le fragment n'a pas eu le temps de terminer l'effet (apparition ou disparition) entre les deux clics. 7.3 Servlet et JSP Le but est ici de créer des servlets permettant de manipuler les clients, les produits et les commandes. La première phase étant la création d'un nouveau client, qu'il puisse s'authentifier et modifier son profil. 7.3.1 Création d un client De manière classique, tous les paramètres nécessaires à la création d'un client sont récupérés : String login = request.getparameter("login"); String password = request.getparameter("password"); String rue = request.getparameter("rue"); Grâce au générateur de contexte, un clientsessionbean est créé auquel se rajoute le nouveau client ainsi crée : ClientSessionBeanRemote sessionbean = GenerateurContext.getClientSessionBeanRemote(); Client c = new Client(login, role, reduc, password, beneficiaire, email, tel, adr, listedescommande); sessionbean.creer(c); La redirection se fait alors vers une JSP personnalisée souhaitant la bienvenue à l'utilisateur identifié avec succès. Sinon, il est invite à s identifier de nouveau via des alertes AJAX. 7.3.2 Identification d un client Comme précédemment, tous les paramètres nécessaires à l'identification d'un client sont récupérés et un clientsessionbean est créé/récupéré grâce au générateur de contexte. 8
String login = request.getparameter("login"); String password = request.getparameter("password"); Sur ce session bean, la méthode identifierclient renvoie le rôle du client, admin ou client. Pour la suite des opérations, en plus d insérer le login à la session, le rôle y est également ajouté, ce qui déterminera les actions possible à une personne connectée. Un client ne pourra pas effectuer les mêmes actions qu'un administrateur. ClientSessionBeanRemote sessionbean = GenerateurContext.getClientSessionBeanRemote(); String role = sessionbean.identifier(login, password); HttpSession session = request.getsession(true); request.setattribute("login", login); Ensuite, une redirection s'effectue en fonction du rôle de la personne connectée. if (role.equals("admin")) { request.getrequestdispatcher("jsp/logadmin.jsp").forward(request,resp onse); else { request.getrequestdispatcher("jsp/logclient.jsp").forward(request,res ponse); 7.3.3 Edition d un profil client Encore une fois, les bons paramètres nécessaires à l'édition d'un client sont récupérés. La page web affectant les valeurs à ces paramètres se charge de passer la valeur de paramètre déjà existante si l'utilisateur ne souhaite pas la modifier. Ensuite, toutes les fonctions disponibles sont appelées dans le haricot pour effectuer les changements. Petit plus, si le nouveau mot de passe n'est pas vide, l'ancien est conservé. Il est également possible pour un administrateur d'éditer tous les clients, de la même manière que précédemment, à ceci prés qu'il peut changer sa réduction, mais pas les paramètres d authentification, login et mot de passe. Pour les produits et les commandes le fonctionnement est assez similaire, en effet les fonctions de création, d'édition, et de suppression fonctionnent de la même manière. A la différence près que selon le rôle de la personne connectée certaines actions ne seront pas disponibles. En effet l'ajout d'un produit dans la base de données ainsi que son édition et sa suppression ne seront accessibles qu'à un administrateur. Mis à part le fait que graphiquement ces actions ne seront disponibles que pour un administrateur connecté, un test sur le rôle est effectué pour éviter toute fraude de la part d'un client malveillant. HttpSession session = request.getsession(); String role = (String)session.getAttribute("role"); if (role.equals("admin")){ try { ProduitSessionBeanRemote sessionbean = GenerateurContext.getProduitSessionBeanRemote(); sessionbean.creerproduit(name, description, prix, categorie, souscategorie, quantite, cheminversimage); 9
catch (Exception e) { request.setattribute("error",e); request.getrequestdispatcher("error.jsp").forward(request, response); else { //renvoyer a l'identification 8 Génération de devis et facture en PDF 8.1 Pourquoi? Afin de conserver trace des prestations qu'a offert le Club Animation, il est nécessaire de conserver un élément qui rende compte de la transaction à une certaine date, indépendamment des évolutions des prix et du parc matériel. Pour cette raison, la génération de fichiers PDF est excellente car une fois écrit, son contenu restera statique même s'il y a des modifications en Back End. Les fichiers générés seront stockés sur serveur grâce à leur n de commande et leur type (facture, devis ou bon de livraison). En ayant le chemin d'accès inscrit en Base de données, il serait ainsi simple de les retrouver pour les renvoyer au client par la suite. A noter que pour plus de portabilité il serait plus judicieux de stocker uniquement le n de facture et que le Front End reconstitue lui-même le chemin d'accès selon sa propre méthode de stockage. 8.2 Intégration générale à l architecture du site L'intégration se fait logiquement du côté où les fichiers sont écrits, c'est à dire en Front End. La génération étant de plus "interactive" (i.e. lancée par l'utilisateur), les Servlets semblent toutes indiquées pour ce genre de traitement. Le traitement de l'intégralité de la tâche n'est pas compliqué en soit : La commande et le client étant fournis (l authentification est donc obligatoire), il suffit de les disséquer pour en tirer les informations importantes et les écrire dans un fichier avec une présentation particulière. La clé du chemin d'accès au fichier doit ensuite être mémorisée dans la base de données pour un appel ultérieur. 8.3 Outils utilisés pour la génération L'idée était au départ de générer un fichier source LaTeX pour le compiler à la volée et générer le PDF. Cette solution a été abandonnée car les librairies LaTeX n'auraient pas forcément été présentes/installables sur le serveur. De plus, ces librairies sont très lourdes puisqu'il y a plusieurs centaines de Mo. A la place, il a été choisi d'utiliser du Java pour générer les PDF. Grâce à la librairie itext (disponible sur http://www.lowagie.com/itext/), il est possible de décrire un document PDF en y ajoutant des éléments au fur et à mesure. Par contre, l'étape d'écriture d'un fichier source est sautée. Pour comparaison avec le LaTeX, la commande du site serait notre fichier source et notre servlet serait le compilateur LaTeX. 10
9 Répartition du travail Nous avons très vite défini notre projet et reparti les tâches selon les envies de chacun. Bastien L. s'est chargé du Back End, épaulé pour la conception papier par Benoit. Benoit a donc aidé sur le Back End, bien que son rôle principal ait été la génération de PDF, via la librairie itext, à partir d'une servlet. Bastien B. a réalisé l'ensemble des servlets, gérant ainsi l'authentification, et les liens entre Beans et JSP, selon les besoins des autres parties. Adrien a conçu les JSP, classe JavaScript et l'ajax du site, aidé par Thibaut. Thibaut s'est occupé du CSS, de l'html et du graphisme, en aidant ensuite Bastien B. sur les servlets et Adrien sur les JSP. Les parties étant clairement définies, le travail a très vite évolué individuellement, et collectivement via un SVN global. Le SVN a vraiment permis d'avoir des tâches autonomes puisque pour les liens avec les autres parties, il était possible d'aller voir ce qui avait été fait. Cependant certaines tâches furent des bloquantes, nécessaires à l'avancement général, notamment le BackEnd dont les interfaces et entités ont du très vite être défini. 10 Problèmes rencontrés 10.1 Castage d'arraylist Lors d'un accès à une collection issue d'un lien OneToMany, le castage en ArrayList lève une exception, expliquant qu'il est impossible de caster le PersistenteBag. Aucune solution n'a été trouvé, d'où l'impossibilité de rattacher une commande à un client (accès possible via l'administrateur pour l'instant, qui récupère la liste complète des commandes), ni de rattacher des produits à une commande. Les modifications des paramètres de fetch, des types de liste (List, ArrayList, Collection) n'ont rien donné. Pour pouvoir cependant présenter une génération de PDF sans réel commande, le modèle entitérelation a été rapidement recopié en Front End de façon à pouvoir tester le générateur sur une commande non vide! 10.2 Internet Explorer vs Firefox Lors de la conception du CSS divers problèmes de compatibilité ont été rencontrés. En effet, IE et FF n'interprètent pas exactement de la même manière le code. De fait, la position de certains boutons est aléatoire, ce qui est très irritant. Suite à plusieurs tentatives de résolution, il s'est avéré que c'était peut être l'insertion de code avec AJAX ainsi que les effets graphiques qui perturberaient la lecture du CSS. 10.3 Adressage relatif des fichiers PDF générés Le problème majeur est posé par la portabilité : comment savoir où vont aller les fichiers, en particulier si on change de machine serveur. On ne peut donc pas utiliser de chemin absolu pour indiquer où stocker les fichiers. Heureusement les chemins relatifs sont utilisables lors de l'écriture du fichier, en écrivant dans le répertoire courant, c'est le répertoire bin de JBOSS qui sera utilisé. Sachant cela, il est possible de les stocker à l endroit souhaité. Vient ensuite la récupération du fichier par la servlet et là les choses sont plus difficiles : en chemin relatifs ou absolus, il n'a pas été possible de récupérer les fichiers générés. Le problème a donc été contourné en mettant le lien hypertexte vers le fichier directement dans la page du client. 11
11 Conclusion Ce projet fut très intéressant de part son intérêt. En effet, construire un site de e-commerce permet d'utiliser les connaissances théoriques dans un but extrêmement précis et dont le résultat est immédiatement visible. D'autre part, la répartition des tâches s'est avérée être un point clé du déroulement du projet. De manière générale, la communication entre membres s'est très bien déroulée, ceci grâce à une bonne entente, une bonne ambiance et au SVN. Cependant, face à la simultanéité des projets et partiels et à la configuration chaotique des différents outils de développement, il nous a été difficile de mener à bien ce projet comme nous l'aurions souhaité. Bien que la majeure partie du site fonctionne, il reste quelques fonctionnalités à implémenter qui mériteraient que l'on se penche dessus plus tard. In fine, ce projet nous a beaucoup apporté tant sur le plan technique que relationnel. Et bien que partiellement inachevé, nous sommes heureux de ce que nous avons pu réaliser en aussi peu de temps. 12