Dans cette étude, nous allons faire une pose et en profiter pour vérifier tout simplement les compétences acquises dans cette première partie consacrée à J2EE. Nous allons élaborer des exemples très simples au travers desquels nous allons justifier les choix des solutions retenues. Du coup, afin d'éviter la complexité, les exemples choisis ne comporteront pas de communication avec une base de données quelconque.
Lorsque nous devons contruire des applications Web, et vu qu'en Java nous avons des technologies un peu concurrentes, avec les servlets et les pages JSP, nous nous posons souvent la question de savoir laquelle des deux est la plus adaptée à mon problème, ou bien même, s'il n'est pas souhaitable d'utiliser les deux ? Doit-on également utiliser systématiquement le modèle MVC ?
Pour cette dernière question, il faut que l'application Web soit un peu conséquence pour que l'investissement vaille le coup. Par ailleurs, il est souhaitable d'utiliser des technologies connexes comme JSF ou struts pour que le résultat soit agréable et facile à mettre en oeuvre.
Sinon que choisir entre servlet et JSP ? En fait, tout dépend si le résultat est l'affichage d'une page Web ou alors de proposer un traitement particulier côté serveur. Dans ce dernier cas, la servlet s'impose puisque nous avons besoin d'écrire essentiellement du code Java. Si vous devez produire une page Web, la question ne se pose pas, il faut prendre la page JSP. Par contre, évitez au maximum de placer du code Java sur cette dernière, sinon c'est très difficile à lire et à maintenir. N'hésitez pas à écrire le code dans des JavaBeans. Ainsi, vous obtenez une séparation entre la présentation et le traitement à réaliser. Toujours pour les pages JSP, n'hésitez pas également à fabriquer des balises personnalisées, avec des outils comme NetBeans, c'est très facile et rapide à mettre au point.
Le premier exemple que nous allons mettre en oeuvre permet d'effectuer des calcul sur des opérations de base. Quatres opérandes au maximum sont pris en comptes. Le traitement du calcul est réalisé côté serveur Web au moyen d'une servlet. Le client, lui, propose les calculs au travers d'un navigateur. L'avantage de ce système, c'est nous avons besoin d'une technologie très légère côté client. Ci-dessous se trouve la page d'accueil de l'application Web :

Voici le résultat retourné par l'application Web :

Cette application Web est composée de deux éléments qui correspondent finalement aux deux pages que nous venons de voir :
Afin que la bonne page d'accueil operation.html soit affichée et que la servlet ServletOpération soit bien celle qui est demandée pour le traitement, vous devez constituer le descipteur de déploiement <web.xml> qui indique, rappelons-le, comment doit se comporter l'application Web suivant les événements proposés :
| web.xml |
|---|
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>Opération</servlet-name> <servlet-class>ServletOpération</servlet-class> </servlet> <servlet-mapping> <servlet-name>Opération</servlet-name> <url-pattern>/Operation</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>operation.html</welcome-file> </welcome-file-list> </web-app> |
| Operation.html |
|---|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Opérations de base</title> </head> <body> <h2>Opérations de base</h2> <form action="Operation"> <hr /> <h4>Opérande 1 : <input type="text" name="operandes" value="" /></h4> <h4>Opérande 2 : <input type="text" name="operandes" value="" /></h4> <h4>Opérande 3 : <input type="text" name="operandes" value="" /></h4> <h4>Opérande 4 : <input type="text" name="operandes" value="" /></h4> <hr /> <input type="reset" value="Tout effacer" /> <input type="submit" value="+" name="operation" /> <input type="submit" value="-" name="operation" /> <input type="submit" value="*" name="operation" /> <input type="submit" value="/" name="operation" /> </form> </body> </html> |
| ServletOpération.java |
|---|
import java.io.*; import java.net.*; import javax.servlet.*; import javax.servlet.http.*; public class ServletOpération extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); int nombre=0; int[] opérandes = new int[4]; char opération = request.getParameter("operation").charAt(0); String[] operandes = request.getParameterValues("operandes"); for(int i=0; i<operandes.length; i++) if (operandes[i].length()!=0) opérandes[nombre++] = Integer.parseInt(operandes[i]); int résultat = opérandes[0]; switch (opération) { case '+' : for (int i=1; i<nombre; i++) résultat += opérandes[i]; break; case '-' : for (int i=1; i<nombre; i++) résultat -= opérandes[i]; break; case '*' : for (int i=1; i<nombre; i++) résultat *= opérandes[i]; break; case '/' : for (int i=1; i<nombre; i++) résultat /= opérandes[i]; break; } out.println("<html>"); out.println("<head>"); out.println("<title>Résultat du calcul</title>"); out.println("</head>"); out.println("<body>"); out.print("<h2>"+ ( nombre > 0 ? opérandes[0] : 0 )); for(int i=1; i<nombre; i++) { out.print(" "+opération + " " + opérandes[i]); } out.println(" = "+ résultat +" </h2>"); out.println("</body>"); out.println("</html>"); out.close(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } } |
Ici, nous avons une bonne partie de traitement, donc pas mal de code Java, et finalement le fait de prendre une servlet pour réaliser la page Web dynamique n'est pas un si mauvais choix que ça. Toutefois, c'est toujours ennuyeux d'avoir systématiquement l'écriture out.println() au moment de la fabrication de la page Web.
Ici, nous réalisons à la fois le même traitement ainsi que la même construction de la page Web dynamique, mais cette fois-ci c'est la page JSP qui s'occupe de tout cela.
Cette application Web est également composée de deux éléments :
Cette fois-ci, le descripteur de déploiement est beaucoup plus réduit, puisque vous avez juste à indiquer la page d'accueil de l'application Web :
| web.xml |
|---|
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <welcome-file-list> <welcome-file>operation.html</welcome-file> </welcome-file-list> </web-app> |
Seule, l'action de la balise <form> est changée. En effet, il est nécessaire de préciser cette fois-ci que c'est la page JSP operation.jsp qui doit être solliciter en lieu et place de la servlet ServletOperation :
| Operation.html |
|---|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Opérations de base</title> </head> <body> <h2>Opérations de base</h2> <form action="Operation.jsp"> <hr /> <h4>Opérande 1 : <input type="text" name="operandes" value="" /></h4> <h4>Opérande 2 : <input type="text" name="operandes" value="" /></h4> <h4>Opérande 3 : <input type="text" name="operandes" value="" /></h4> <h4>Opérande 4 : <input type="text" name="operandes" value="" /></h4> <hr /> <input type="reset" value="Tout effacer" /> <input type="submit" value="+" name="operation" /> <input type="submit" value="-" name="operation" /> <input type="submit" value="*" name="operation" /> <input type="submit" value="/" name="operation" /> </form> </body> </html> |
La page JSP remplace donc la servlet. Sur la partie haute de la page (lignes 5 à 20), nous retrouvons le même traitement que pour la servlet. Vu que le codage est séparé de la partie présentation, c'est pas mal, par contre en dessous, ce qui correspond normalement à la mise en page Web, nous trouvons un mélange incongru de balises HTML et de codage Java. Dans cette partie basse (lignes 25 à 38), nous avons vraiment du mal à comprendre ce qui est écrit. Il faut vraiment proscrire ce genre d'écriture.
| Operation.jsp |
|---|
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "http://www.w3.org/TR/html4/loose.dtd"> 3 4 <% 5 int nombre=0; 6 int[] opérandes = new int[4]; 7 8 char opération = request.getParameter("operation").charAt(0); 9 String[] operandes = request.getParameterValues("operandes"); 10 11 for(int i=0; i<operandes.length; i++) 12 if (operandes[i].length()!=0) opérandes[nombre++] = Integer.parseInt(operandes[i]); 13 14 int résultat = opérandes[0]; 15 16 switch (opération) { 17 case '+' : for (int i=1; i<nombre; i++) résultat += opérandes[i]; break; 18 case '-' : for (int i=1; i<nombre; i++) résultat -= opérandes[i]; break; 19 case '*' : for (int i=1; i<nombre; i++) résultat *= opérandes[i]; break; 20 case '/' : for (int i=1; i<nombre; i++) résultat /= opérandes[i]; break; 21 } 22 %> 23 24 25 <html> 26 <head> 27 <title>Résultat du calcul</title> 28 </head> 29 <body> 30 <h2><%= nombre > 0 ? opérandes[0] : 0 %> 31 <% 32 for(int i=1; i<nombre; i++) { 33 %> 34 <%= opération %> <%= opérandes[i] %> 35 <% } %> 36 = <%= résultat %></h2> 37 </body> 38 </html> |
Franchement, si nous prenons une page JSP pour tout faire, c'est pas terrible. Dans ce cas là, le choix de la servlet paraît même plus adapté. Toutefois, J'ai bien spécifié que lorsque le résultat est une page Web, il est préférable de prendre directement une page JSP, alors comment faire ? Il faut quand même utiliser une page JSP, mais surtout, il est nécessaire de séparer le code de la partie présentation. Pour réaliser cette séparation, il suffit d'utiliser une classe Java qui s'occupe de tout le traitement, avec en plus des propriétés adaptées à la page Web. Lorsque ces critères sont respectés, la classe Java porte le nom de JavaBean.
Nous allons donc reprendre le même sujet en concervant toutefois la page JSP (très remaniée), en prévoyant en plus un composant JavaBean qui s'occupera de tout le calcul nécessaire au traitement.
Cette fois-ci l'application Web est composée de trois éléments :
Cette fois-ci, la page JSP est très réduite. Ce qui est normal puisque le résultat demandé est une simple ligne d'affichage. Sur la partie haute de la page, nous avons la création de l'objet calcul qui représente le JavaBean bean.Operation. Dans la ligne suivante, nous demandons à spécifier automatiquement les propriétés relatives aux paramètres données par la requête HTTP. Les paramètres envoyés par la requête HTTP sont respectivement operandes et operation. Nous réclamons ensuite dans l'affichage, la valeur de la propriété resultat du bean calcul. Cette propriété s'occupe de mettre en forme l'affichage du résultat du calcul.
| Operation.jsp |
|---|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <jsp:useBean id="calcul" class="bean.Operation" /> <jsp:setProperty name="calcul" property="*" /> <html> <head> <title>Résultat du calcul</title> </head> <body> <h2><jsp:getProperty name="calcul" property="resultat" /></h2> </body> </html> |
Je rappelle qu'un JavaBean est avant tout une simple classe Java. Pour être considéré comme un JavaBean, il faut toutefois respecter deux critères :
Souvent les propriétés des JavaBeans correspondent à des attributs, mais ce n'est pas indispensable. Remarquez d'ailleurs, dans le code ci-dessous, qu'il existe une différence entre le type de l'attribut operandes et le paramètre operandes passé en argument de la méthode setOperandes().
| bean.Operation.java |
|---|
package bean; import java.util.*; public class Operation { private int[] operandes; private char operation; private int resultat; public Operation() { } public void setOperandes(String[] operandes) { int nombre=0; for (int i=0; i<operandes.length; i++) if (operandes[i].length()!=0) nombre++; this.operandes = new int[nombre]; for (int i=0; i<operandes.length; i++) if (operandes[i].length()!=0) this.operandes[i] = Integer.parseInt(operandes[i]); } public void setOperation(char operation) { this.operation = operation; } private void calcul() { resultat = operandes[0]; switch (operation) { case '+' : for (int i=1; i<operandes.length; i++) resultat += operandes[i]; break; case '-' : for (int i=1; i<operandes.length; i++) resultat -= operandes[i]; break; case '*' : for (int i=1; i<operandes.length; i++) resultat *= operandes[i]; break; case '/' : for (int i=1; i<operandes.length; i++) resultat /= operandes[i]; break; } } public String getResultat() { calcul(); String chaîne = ""+operandes[0]; for(int i=1; i<operandes.length; i++) chaîne = chaîne+" "+operation + " " + operandes[i]; chaîne = chaîne +" = "+ resultat; return chaîne; } } |
Outre les méthodes qui sont en relation avec la page JSP et qui correspondent aux propriétés désirées, nous pouvons trouver d'autres méthodes ainsi, qu'éventuellement d'autres attributs. Ces éléments supplémentaires sont là pour permettre une meilleure gestion du JavaBean et surtout, une plus grande clarté en séparant bien les différentes tâches à réaliser. C'est le cas ici avec la méthode calcul() qui est privée, et qui ne peut donc être utilisée que par une autre méthode, en l'occurence ici, par la méthode qui représente la propriété resultat.
Cette fois-ci, l'architecture de cette application Web est vraiment idéale. Nous avons bien une séparation entre la partie visuelle représentée par la page Web et le traitement proprement dit mis en oeuvre par le JavaBean. Cette séparation de compétence est très utile. Globalement, nous obtenons une plus grande clarté. La maintenance s'en trouvera d'autant plus facilité.
Nous allons maintenant traité à peu prêt le même type de sujet que précédemment. Toutefois, cette fois-ci il sera composé de pratiquement tout l'ensemble des technologies que nous avons découvertes dans les études précédentes. Voici d'ailleurs ces principaux éléments :
Il est composé d'une seule pas JSP, découpée en plusieurs fragments, qui capitalise l'ensemble des événements proposés par l'utilisateur. Un affichage est adapté à la situation et une nouvelle orientation est proposée suivant le cas de figure.
Voici donc comment se présente notre application Web. La page d'accueil est également la page principale de l'application en ce sens que ce sera toujours elle qui sera visible quelque soit les requêtes proposées par l'utilisateur client, et son apparence varie en fonction de ses désirs.

Notamment, il est possible de choisir le nombre d'opérandes afin d'effectuer les calculs requis. Cela se fait au travers d'une liste dont le nombre de valeurs est configurable dans le descripteur de déploiement <web.xml> de l'application Web. Il est également possible de visualiser ou pas l'historique des calculs proposés par l'opérateur. Il est même permis de récupérer cet historique sous forme de fichier texte.
Remarquez au passage le changement du libellé du bouton suivant que l'historique est affiché ou pas.
.

Lorsqu'une erreur de type division par zéro survient, une page d'erreur est alors sollicitée et reprend une grande partie de la présentation de la page principale de l'application Web. Seule la partie propre au résultat est changée afin d'afficher un message d'alerte approprié. Par ailleurs, la partie historique n'est plus proposée.

Je vais commencer comme d'habitude par le descripteur de déploiement qui décrit le comportement souhaitable de l'application Web. Voici les éléments qui le compose :
| web.xml |
|---|
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <context-param> <param-name>NombreMaxi</param-name> <param-value>7</param-value> </context-param> <servlet> <servlet-name>Fichier</servlet-name> <servlet-class>servlet.Fichier</servlet-class> </servlet> <servlet-mapping> <servlet-name>Fichier</servlet-name> <url-pattern>/Historique.txt</url-pattern> </servlet-mapping> <filter> <filter-name>FiltreJournal</filter-name> <filter-class>servlet.Journal</filter-class> </filter> <filter-mapping> <filter-name>FiltreJournal</filter-name> <url-pattern>/Operation.jsp</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file> Operation.jsp </welcome-file> </welcome-file-list> </web-app> |
Cette page est très réduite. Elle comporte juste l'ossature du document HTML et fait ensuite appel aux différents fragments de page qui s'occupe chacun d'une tâche particulière. Généralement, les fragments de page sont très souvent utilisés pour proposer un en-tête du site Web ainsi qu'un pied de page commun. Toutefois, rien n'empêche d'utiliser cette technique afin de réduire la complexité en différents sous-ensembles. Ici, les fragments sont :
| Operation.jsp |
|---|
<%@page errorPage="/WEB-INF/erreur.jsp"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@include file="/WEB-INF/jspf/style.jspf"%> <html> <head> <title>Opérations de base</title> </head> <body> <h2>Opérations de base</h2> <%@include file="/WEB-INF/jspf/nombre.jspf"%> <%@include file="/WEB-INF/jspf/operandes.jspf"%> <%@include file="/WEB-INF/jspf/calcul.jspf"%> <%@include file="/WEB-INF/jspf/historique.jspf"%> </body> </html> |
Cette page principale déclare une page d'erreur erreur.jsp qui sera donc active si une erreur se produit sur n'importe lequel des fragments de page. Toutefois, l'erreur recensée est la division par zéro qui ne sera donc éventuellement provoquée que par le fragment de page correspondant, c'est-à-dire : operandes.jspf.
Lorsque différentes erreurs sont suceptibles de se produire, il faut mettre en oeuvre plusieurs pages d'erreur et aiguiller l'application Web au moyen du descripteur de déploiement en rapport avec le type d'erreur rencontré. Ce n'est pas le cas ici, c'est pour cela que cette simple déclaration suffit.
Voici donc la page d'erreur. Nous retrouvons la même ossature que la page principale. Seule une partie est enlevée afin de proposer à la place l'affichage de l'erreur "Attention à la division par zéro". Nous voyons là l'intérêt d'avoir découpé la page principale en plusieurs fragments. Ainsi, la page d'erreur est également très réduite puisqu'elle fait appel aux mêmes fragments. Du coup, nous avons l'impression de rester sur la même page.
| erreur.jsp |
|---|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@include file="/WEB-INF/jspf/style.jspf"%> <html> <head> <title>Opérations de base</title> </head> <body> <h2>Opérations de base</h2> <%@include file="/WEB-INF/jspf/nombre.jspf"%> <%@include file="/WEB-INF/jspf/operandes.jspf"%> <h2 class="erreur">Attention à la division par zéro</h2> </body> </html> |
Nous allons maintenant passer à l'étude des différents fragments de page. Nous commençons dans l'ordre d'apparition par le fragment style.jspf. Cette partie s'occupe essentiellement de l'aspect visuel de l'ensemble des éléments qui constituent la page. Pour cela, nous utilisons la technique des CSS. Grâce à cette technique, vous pouvez changer l'aspect des balises lorsqu'elles sont utilisées dans une page Web, ou même créer de nouveaux éléments qui pourront être utiliser sur n'importe quel type de balise.
Je ne vais pas beaucoup m'étendre sur cette partie puisque je ne vous est proposé aucun cours à ce sujet. Vous pouvez d'ailleurs ne pas le prendre en compte, le fonctionnement demeurera identique. Toutefois, l'aspect est quand même plus agréable.
Le très gros avantage de la technique des CSS, c'est là aussi de faire une séparation entre le contenu d'une page Web et son aspect visuel. CSS ne s'occupe que de cette dernière partie. Du coup, il est même possible de prendre du balisage XML en lieu et place du HTML puisque normalement les balises HTML s'occupent déjà du formattage de l'information. Effectivement, lorsque vous prenez, par exemple, la balise <H2>, vous spécifier d'avoir une tête de chapitre d'une certaine grosseur. Lorsque tous les navigateurs utilisés prendront bien en compte le XML, il sera vraiment préférable d'abandonner le HTML au profit du XML, surtout d'ailleurs pour les pages Web dynamiques.
| style.jspf |
|---|
<style type="text/css"> body { font-family: Verdana, Arial, Helvetica, sans-serif; } h2 { color: #669900; background-color: #66FF66; padding: 10px; border : groove; } h3, .operandes { color: #0033CC; border: thin dashed; padding: 5px; background-color: #FFFFCC; text-indent: 7px; } h4 { margin: 3px; } .erreur { color: #FF0000; } </style> |
Ici, nous définissons quelques aspects que prendrons les balises lorsque nous avons besoin :
Nous pouvons créer également de nouveau types d'élements qui pourrons être utilisés avec n'importe laquelle des balises HTML. Ces éléments s'appellent alors des classes, et pour qu'ils soient désignés comme tel, le nom doit impérativement avoir comme préfixe un point. C'est le cas ici de .operandes et de .erreur. Lorsque vous aurez besoin d'utiliser ces classes, il faudra alors solliciter l'attribut class de la balise qui la prendra en compte, par exemple :
<h2 class="erreur">Attention à la division par zéro</h2>
La classe .operandes reprend le même comportement visuel que <h3>, et pour .erreur, nous demandons juste que le texte soit écrit en rouge.
Ce fragment permet de gérer le nombre d'opérandes qui seront nécessaires afin d'effectuer le calcul de base adapté au désir de l'utilisateur. N'oubliez pas qu'il faut qu'il y ait au maximum, une séparation entre l'aspect visuel de la page et le traitement sous-jacent. Si un traitement est effectivement demandé, il y aura donc systématiquement un JavaBean correspondant. C'est le cas ici avec le JavaBean bean.Nombre.
| nombre.jspf |
|---|
<jsp:useBean id="nombre" class="bean.Nombre" scope="session" /> <jsp:setProperty name="nombre" property="valeur" param="valeur" /> <jsp:setProperty name="nombre" property="maxi" value="${initParam.NombreMaxi}" /> <h3> <form action="Operation.jsp"> Nombre d'opérandes : <select name="valeur"> ${nombre.options} </select> <input type="submit" value="Valider ce choix" /> </form> </h3> |
| bean.Nombre.java |
|---|
package bean; public class Nombre { private int valeur = 2; private int maxi = 2; public Nombre() { } public void setValeur(int n) { valeur = n; } public int getValeur() { return valeur; } public void setMaxi(int n) { maxi = n; } public String getOptions() { String résultat = ""; for (int i=2; i<=maxi; i++) résultat = résultat +"<option "+ (i==valeur ? "selected" : "") +">"+i+"</option>\n"; return résultat; } } |
Ce fragment de page s'occupe en premier de créer l'objet bean nombre relatif à la classe JavaBean bean.Nombre. Cet objet existe pendant toute la durée de la session. Ainsi, si l'opérateur choisi de travailler avec trois opérandes pour ses calculs, cela lui évite d'en refaire la demande systématiquement.
Ensuite, nous récupérons l'ensemble des paramètres issue de la requête HTTP. Bien entendu, seuls les paramètres correspondant aux propriétés du JavaBean nombre sont pris en compte par ce dernier. Si aucun paramètre le concernant n'est proposé dans la requête, comme c'est par exemple le cas lors de la première connexion, alors le bean nombre ne change pas d'état. Ici, nous avons besoin dans un premier temps de récupérer éventuellement le paramètre de la requête HTTP valeur qui représente la valeur du nombre d'opérandes désiré par l'opérateur. Pour cela, nous demandons un changement de propriété (<jsp:setProperty>) en proposant l'association entre le paramètre de la requête (param) et l'attribut correspondant du bean nombre (property).
Nombre possède en fait deux propriétés, valeur et maxi. La première est éventuellement changée uniquement lorsqu'une requête HTTP est envoyée dans ce sens. Cela se produit lorsque nous appuyons sur le bouton "Valider ce choix". Remarquez au passage que les attributs possèdent des valeurs non-nulles par défaut. Ainsi au démarrage de la session, le nombre d'opérandes est fixé par la valeur 2.
Nous proposons ensuite une deuxième demande de changement de propriété sur ce même bean mais en précisant cette fois-ci le nom de la propriété concernée. Il s'agit de la propriété maxi, et le changement proposé devra donc être impérativement prise en compte par le bean nombre. Ici, en l'occurence, la valeur proposée est issue du paramètre de contexte de l'application Web (initParam) défini par le descripteur de déploiement. Ce paramètre s'appelle NombreMaxi.
La technique qui consiste à utiliser un paramètre de contexte est intéressante. En effet, lorsque vous désirez changer, par exemple, le nombre maximum d'opérandes qui apparaît dans la liste de choix, vous n'avez pas besoin de tout recompiler, il suffit simplement de changer la valeur proposée, directement dans le descripteur de déploiement.
Ce fragment intègre ensuite une balise <form> dont l'action est de refaire appel à la page principale Operation.jsp de nouveau. Dans cette balise, nous trouvons également deux autres balises imbriquées : <select> qui propose la liste du nombre d'opérandes et le bouton "Valider ce choix" qui sert de confirmation de la part de l'opérateur. Lorsque l'opérateur clique sur ce bouton, la requête HTTP est effectivement envoyée à la page Operation.jsp avec en plus le paramètre valeur contenant le nombre d'opérandes choisi.
Pour avoir le nombre d'options variables par rapport au nombre maximum d'opérandes possibles, remarquez bien que la page JSP sollicite la propriété options du bean nombre. Cette dernière fabrique alors une chaîne de caractère qui intègre les balises imbriquées <option> de la balise <select> avec en plus la mise en place de l'attribut selected suivant le dernier nombre d'opérande choisi par l'opérateur. Ainsi, nous pouvons effectuer une suite d'opérations de base toujours avec le même nombre d'opérandes.
La mémorisation du nombre d'opérandes impose que ce bean.Nombre soit placée dans la session, ce qui se fait au moyen de l'attribut scope de la balise <jsp:useBean>.
Ce fragment de page nous permet de récupérer les valeurs saisies par l'opérateur afin d'effectuer le calcul de l'opération de base souhaitée. Pour cela, nous avons besoin de choisir le type d'opération ainsi que la valeur de chacun des opérandes. Nous intégrons donc une nouvelle balise <form> dont l'action est une nouvelle fois Operation.jsp. La requête HTTP est envoyée à la page principale par l'intermédiaire d'un des boutons représentant le type d'opération à traiter. Deux paramètres alors sont envoyés avec la requête, le paramètre operandes qui est un tableau de valeur (vue qu'il y a plusieurs opérandes), et le paramètre operation qui indique le caractère correspondant au symbole de l'opération à traiter.
| operandes.jspf |
|---|
<%@taglib uri="/balises" prefix="tag"%> <div class="operandes" > <form action="Operation.jsp"> <tag:repeter fois="${nombre.valeur}"> <h4>Opérande ${indice} : <input type="text" name="operandes" value="" width="5" /> </h4> </tag:repeter> <h4>..................... <input type="submit" value="+" name="operation" /> <input type="submit" value="-" name="operation" /> <input type="submit" value="*" name="operation" /> <input type="submit" value="/" name="operation" /> </h4> </form> </div> |
Le nombre d'opérandes est variable. Du coup, afin d'éviter d'écrire du code Java à l'intérieur de ce fragment de page, notamment avec la mise en place d'une itérative de type for, j'ai plutôt souhaité créer une nouvelle balise personnalisée que je nomme <repeter>. Cette balise comporte un attribut dénommé fois dont la valeur est ici précisé par la propriété valeur du bean nombre. Vous remarquez également la présence de l'attribut indice qui est utile afin de placer une numérotation automatique sur les opérandes. Cet attribut est également prise en charge par notre balise personnalisée <repeter>.
La première ligne de ce fragment de page déclare l'utilisation d'une balise personnalisée dont la bibliothèque de balise se situe à l'uri /balises. Chaque balise de cette bibliothèque (ici, il n'y en a qu'une) devra également utiliser l'espace de nom tag.
A chaque fois que vous créez une balise personnalisée, vous devez le faire en deux étapes par l'intermédiaire de deux structures :
La première démarche consiste donc à implémenter une bibliothèque qui sert de descripteur de balises, ici balises.tld. Ce fichier décrit donc l'ensemble des balises personnalisées que comporte votre application Web. Ici, nous avons besoin de décrire une seule balise.
| balises.tld |
|---|
<?xml version="1.0" encoding="UTF-8"?> <taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"> <tlib-version>1.0</tlib-version> <short-name>balises</short-name> <uri>/balises</uri> <tag> <name>repeter</name> <tag-class>tag.Repeter</tag-class> <body-content>scriptless</body-content> <attribute> <name>fois</name> <required>true</required> <type>int</type> <rtexprvalue>yes</rtexprvalue> </attribute> </tag> </taglib> |
La première partie de ce descripteur est commune à toutes les balises de la bibliothèque avec, le numéro de version, l'espace de nom utilisée et l'URI de localisation. Cette partie est obligatoire, mais seule la balise <uri> me paraît intéressante. Faites en sorte d'avoir l'URI la plus courte possible comme ici /balises.
Ensuite, chaque balise est délimitée par une balise <tag>. Dans cette balise, vous spécifier le nom qui apparaitra dans la page JSP (<repeter>), la classe correspondante qui sera lancer afin d'interpréter le code interne correspondant ( <tag-class>). Ensuite, nous devons indiquer impérativement si cette balise possède un corps et si ce corps doit être copié tel quel ou au contraire interprété (<body-content>) . En ce qui nous concerne, le corps est interprété puisque nous avons besoin d'utiliser l'attribut de page : indice. Du coup, nous devons spécifier la valeur scriptless.
Ensuite, nous devons décrire la valeur de l'attribut fois correspondant à la balise <repeter>. Ainis, il faut préciser son nom (<name>), si il est obligatoire ou pas (<required>), quel est son type (<type>) et surtout si la valeur proposée à l'attribut est une constante ou une valeur délivrée par une autre entité comme ici par la propriété valeur du bean nombre. Dans ce cas là, il est nécessaire de valider la balise <rtexrvalue>.
Dans la deuxième démarche nous allons écrire le codage correspondant au traitement souhaité par l'utilisation de cette balise. Ici, nous désirons que le contenu que nous plaçons à l'intérieur de <repeter> soit écrite x fois avec la possibilité supplémentaire de gérer un indice dont la première valeur débute à 1. Ici, le codage s'exprime à l'intérieur du gestionnaire de balise tag.Rapeter.
| tag.Repeter.java |
|---|
package tag; import java.io.IOException; import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.*; public class Repeter extends SimpleTagSupport { private int fois; public void setFois(int value) { this.fois = value; } public void doTag() throws JspException, IOException { JspWriter pageJSP = getJspContext().getOut(); JspFragment corps = getJspBody(); for (int i=0; i<fois; i++) { this.getJspContext().setAttribute("indice", i+1); corps.invoke(pageJSP); } } } |
Ainsi, le codage doit être implémenté dans une classe qui, lorsque elle décrit le fonctionnement d'une balise personnalisée, s'appelle un gestionnaire de balise. Cette classe doit respecter les spécifications d'un JavaBean et doit implémenter et doit hériter de la classe SimpleTagSupport.
Nous retrouvons effectivement le même type de démarche que pour les JavaBeans. En effet, les attributs des balises correspondent aux attributs de la classe. Ici, nous devons nous occuper de l'attribut fois. Nous le retrouvons effectivement comme attribut de la classe tag.Repeter. Son type est bien un entier.
Ensuite