Introduction à STRUTS2 par l'exemple


précédentsommairesuivant

IX. Exemple 07 - Les balises de formulaire

Nous allons construire et exploiter le formulaire suivant :

Image non disponible

Nous allons étendre le concept d'injection de paramètres vu pour un champ de saisie texte aux autres éléments Html d'un formulaire.

IX-A. Le projet Netbeans

Image non disponible

  • en [1], les vues du projet [Formx.jsp]
  • en [2], le fichier de configuration de Struts et les messages internationalisés
  • en [3], les actions [Formx.java] et un autre fichier de configuration de Struts.

IX-B. Configuration de Struts

Le fichier [struts.xml] est le suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <constant name="struts.custom.i18n.resources" value="messages" />
  
  <include file="example/example.xml"/>

  <package name="default" namespace="/" extends="struts-default">
    <default-action-ref name="index" />
    <action name="index">
      <result type="redirectAction">
        <param name="actionName">Form</param>
        <param name="namespace">/example</param>
      </result>
    </action>
  </package>
</struts>
  • ligne 9 : inclut un autre fichier de configuration [example.xml]. C'est lui qui va configurer les actions.
  • lignes 11-19 : le package default. Définit une adresse de redirection pour l'Url /. Elle sera redirigée vers l'Url /example/Form.action.

Le fichier [example.xml] qui configure les actions est le suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <package name="example" namespace="/example" extends="struts-default">
    <action name="Form" class="example.Form">
      <result name="success">/example/Form.jsp</result>
    </action>
    <action name="Form1" class="example.Form1">
      <result name="success">/example/Form1.jsp</result>
    </action>
    <action name="Form2" class="example.Form2">
      <result name="success">/example/Form2.jsp</result>
    </action>
  </package>
</struts>
  • lignes 7-17 : définissent les actions /example/Form, /example/Form1, /example/Form2/example est le namespace (ligne 7) et Formx les actions.
  • lignes 8-10 : l'exécution de l'action Form produira l'affichage de la vue /example/Form.jsp.
  • lignes 11-13 : l'exécution de l'action Form1 produira l'affichage de la vue /example/Form1.jsp.
  • lignes 14-16 : l'exécution de l'action Form2 produira l'affichage de la vue /example/Form2.jsp.

IX-C. Les fichiers des messages

Nous ne nous attarderons pas sur l'internationalisation du projet. Nous l'avons déjà étudiée dans l'exemple 01. Nous donnons le contenu du fichier [messages.properties] afin que le lecteur puisse comprendre les vues qui vont suivre.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
Form.francais=Fran\u00E7ais
Form.anglais=Anglais
Form.titre=Struts 2 - les tags de formulaire
Form.message=Struts 2 - les tags de formulaire
Form.langues=langues
Form.textfield=1-textfield
Form.password=2-password
Form.textarea=3-textarea
Form.select1=4-select (multiple=false, size=1)
Form.select1.header=<-- select1 -->
Form.select2=5-select (multiple=false, size=3)
Form.select3=6-select (multiple=true, size=3)
Form.radio=7-radio
Form.checkbox=8-checkbox
Form.checkboxlist=9-checkboxlist
Form.hidden=10-hidden
Form.submitText=Valider
Form.buttonRazText=Raz
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.textfield=1-textfield
Confirmation.password=2-password
Confirmation.textarea=3-textarea
Confirmation.select1=4-select (multiple=false, size=1)
Confirmation.select2=5-select (multiple=false, size=3)
Confirmation.select3=6-select (multiple=true, size=3)
Confirmation.radio=7-radio
Confirmation.checkbox=8-checkbox
Confirmation.checkboxlist=9-checkboxlist
Confirmation.hidden=10-hidden

IX-D. La vue [Form.jsp] - partie saisie

Son apparence visuelle est la suivante :

Image non disponible

C'est la suivante :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title><s:text name="Form.titre"/></title>
    <s:head/>
  </head>

  <body background="<s:url value="/ressources/standard.jpg"/>">
    <h2><s:text name="Form.message"/></h2>
    <h3><s:text name="Form.langues"/></h3>
    <ul>
      <li>
        <s:url id="url" action="Form">
          <s:param name="request_locale">en</s:param>
        </s:url>
        <s:a href="%{url}"><s:text name="Form.anglais"/></s:a>
      </li>
      <li>
        <s:url id="url" action="Form">
          <s:param name="request_locale">fr</s:param>
        </s:url>
        <s:a href="%{url}"><s:text name="Form.francais"/></s:a>
      </li>
    </ul>
    <s:form name="formulaire">
      <s:textfield name="textfield" key="Form.textfield" />
      <s:password name="password" key="Form.password"/>
      <s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
      <s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
      <s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
      <s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
      <s:radio name="radio" list="radioValues" key="Form.radio"/>
      <s:checkbox name="checkbox" key="Form.checkbox"/>
      <s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
      <s:hidden name="hidden" key="Form.hidden"/>
      <s:submit key="Form.submitText" name="submitText"/>
    </s:form>
    <hr/>
 ...
  </body>    
  • le formulaire commence ligne 26 et se termine ligne 38. Ligne 26, l'attribut action est absent. Cet attribut précise à quelle action, les données du formulaire seront postées. En l'absence de l'attribut action elles seront postées à l'action qui a conduit à l'affichage de la vue, ici l'action [Form].
  • ligne 27 : un champ de saisie. L'attribut key précise son libellé. L'attribut name est le nom du paramètre qui sera posté. La chaîne postée pour ce champ sera de la forme :
    textfield=texte_saisi
    Le nom du paramètre correspond à un champ de l'action [Form]. La valeur du champ de saisie texte_saisi sera ici injectée dans le champ textfield de l'action [Form]. Inversement, si la vue [Form.jsp] est affichée suite à l'action [Form], la valeur du champ de saisie sera celle du champ textfield de l'action [Form]. Ce champ est donc utilisé en lecture et écriture. La classe [Form] doit avoir les méthodes getTextField et setTextField pour cela.

    Ce raisonnement est valable pour toutes les balises de saisie qui vont suivre. Nous ne le répéterons pas.
  • ligne 28 : saisie d'un mot de passe. La chaîne postée à l'action [Form] sera de la forme

    password=mot_de_passe_saisi

    Un champ password avec ses get / set doit exister dans l'action [Form].
  • ligne 29 : saisie d'un texte multi-lignes dans une zone de 5 lignes et 40 colonnes. La chaîne postée à l'action [Form] sera de la forme

    textarea=saisie

    Un champ textarea avec ses get / set doit exister dans l'action [Form].
  • ligne 30 : une liste déroulante (size=1) à sélection unique. Une seule valeur de la liste peut être sélectionnée. La chaîne postée à l'action [Form] sera de la forme :

    select1=valeur_sélectionnée

    Un champ select1 avec ses get / set doit exister dans l'action [Form].

    L'attribut key est le libellé de la liste. L'attribut list définit la liste des valeurs à mettre dans le combo. Ici, la méthode getSelect1Values de l'action [Form] sera appelée pour remplir le combo. Cette méthode peut rendre une collection, un dictionnaire ou un tableau. Ici, elle rendra un tableau de chaînes de caractères [chaine1, chaine2, ...] qui générera le code Html suivant :

    <option value="chaine1">chaine1</option>
    <option value="chaine2">chaine2</option>


    Le texte entre les balises <option>...</option> sera affiché dans le combo. L'attribut value désigne la valeur à poster si l'option est sélectionnée par l'utilisateur. Ici l'attribut value et le texte affiché dans le combo sont identiques. Le plus souvent, ce n'est pas le cas. Si la deuxième option est sélectionnée, la chaîne suivante sera postée à l'action [Form] :

    select1=chaine2

    Le champ [Form].select1 recevra alors la valeur chaine2. Inversement, si au moment de l'affichage du formulaire, ce champ vaut chaine3, alors visuellement, le 3ième élément

    <option value="chaine3">chaine3</option>

    apparaîtra sélectionné dans le combo.

    L'attribut headerValue fixe le texte à afficher comme 1ère option du combo et headerKey la valeur à poster si cette option est choisie par l'utilisateur.
  • ligne 31 : là encore une liste de taille 3 (size=3) : contrairement à la précédente liste où un seul élément est visible, ici 3 éléments de la liste seront visibles. Le mode de sélection reste le même. On ne peut sélectionner qu'un élément.
  • ligne 32 : de nouveau une liste mais à sélection multiple (multiple=true). Dans ce cas, la valeur postée à l'action [Form] sera de la forme :

    select3=chaine2&select3=chaine5

    si les options chaine2 et chaine5 ont été sélectionnées. Lorsque plusieurs valeurs sont postées pour un même paramètre, ici select3, l'action doit avoir un champ ayant le nom du paramètre et être de type tableau. Donc par exemple, ici l'action [Form] pourrait avoir un champ du genre :

    String[] select3 ;

    et les méthodes get / set qui vont avec. Le tableau select3 recevra alors le tableau de chaînes de caractères [chaine2,chaine5]. Inversement, à l'affichage de la vue [Form.jsp], les valeurs du champ [Form].select3 déterminent les options de la liste select3 qui apparaîtront sélectionnées. On est toujours en lecture / écriture.
  • ligne 33 : un groupe de boutons radio. Le libellé du groupe est fourni par l'attribut key. Les libellés des boutons individuels sont fournis par l'attribut list. La valeur de cet attribut est le nom d'une méthode de l'action [Form] qui doit rendre une collection, un dictionnaire ou un tableau. Ici, la méthode [Form].getRadioValues rendra un tableau de chaînes de caractères [chaine1,chaine2,...] qui génèrera les balises Html suivantes :

    <input type="radio" name="radio" ... value="chaine1"/>chaine1
    <input type="radio" name="radio" ... value="chaine2"/>chaine2

    Si le bouton radio chaine2 est coché, la valeur postée sera

    radio=chaine2

    et cette valeur sera injectée dans le champ [Form].radio.
  • ligne 34 : une case à cocher. Si elle est cochée, la chaîne de paramètres suivante sera postée à l'action [Form]

    checkbox=true

    Si elle n'est pas cochée, aucune chaîne de paramètres n'est postée. Struts 2 a un mécanisme interne qui fait que tout se passe comme si la chaîne

    checkbox=false

    avait été postée.
  • ligne 35 : une liste de cases à cocher. On peut en cocher plusieurs. Le libellé du groupe est fourni par l'attribut key. Les libellés des cases à cocher individuelles sont fournis par l'attribut list. La valeur de cet attribut est le nom d'une méthode de l'action [Form] qui doit rendre une collection, un dictionnaire ou un tableau. Ici, la méthode [Form].getCheckboxlistValues rendra un tableau de chaînes de caractères [chaine1,chaine2,...] qui génèrera les balises Html suivantes :

    <input type="checkbox" name="checkboxlist" ... value="chaine1"/>chaine1
    <input type="checkbox" name="checkboxlist" ... value="chaine2"/>chaine2


    Si l'utilisateur sélectionne les cases libellées chaine2 et chaine5, la chaîne de caractère suivante sera postée à l'action [Form] :

    checkboxlist=chaine2&checkboxlist=chaine5

    Le tableau [chaine2, chaine5] sera affecté au champ [Form].checkboxlist qui doit donc être de type tableau de chaînes de caractères comme pour les listes à sélection multiple. Inversement, à l'affichage de la vue [Form.jsp], les valeurs du champ [Form].checkboxlist déterminent les cases à cocher qui seront cochées.
  • ligne 36 : un champ caché. Un champ caché est un champ qui est posté sans être saisi par l'utilisateur. Sa valeur est fixé par le programmeur. Ici le champ caché prendra sa valeur du champ [Form].hidden. Cette même valeur sera postée sous la forme :

    hidden=qqchose

    et réaffecté au champ [Form].hidden.
  • ligne 37 : un bouton de type submit. Un clic sur ce bouton, postera toutes les valeurs du formulaire à l'action [Form]. La chaîne des paramètres postés ressemblera à ceci :

 
Sélectionnez
textfield=texte&password=&textarea=ligne1%0D%0Aligne2%0D%0A&select1=z
%C3%A9ro&select2=trois&select3=z
%C3%A9ro&select3=deux&__multiselect_select3=&radio=bleu&checkbox=true&__checkbox_
checkbox=true&checkboxlist=v
%C3%A9lo&checkboxlist=bus&__multiselect_checkboxlist=&hidden=initial&submitText=Valider 

IX-E. L'action [Form] - partie saisie

Son code est le suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
package example;

import com.opensymphony.xwork2.ActionSupport;

public class Form extends ActionSupport {

  // constructeur sans paramètre
  public Form() {
  }
  // champs du formulaire
  private String textfield = "texte";
  private String password = "secret";
  private String textarea = "ligne1\nligne2\n";
  private String select1 = "zéro";
  private String[] select1Values = new String[]{"zéro", "un", "deux"};
  private String select2 = "trois";
  private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
  private String[] select3 = new String[]{"zéro", "deux"};
  private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
  private String radio = "bleu";
  private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
  private Boolean checkbox = false;
  private String[] checkboxlist = new String[]{"vélo", "bus"};
  private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
  private String hidden = "initial";
  private String submitText;

  // valeurs sélectionnées dans champ select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  // valeurs sélectionnées dans champ checkboxlist
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // méthode utilitaire
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
  }

// getters et setters des champs
  ....
}
  • ligne 1 : le champ associé à la balise textfield du formulaire. Servira à initialiser ce champ de saisie aussi bien qu'à en récupérer la valeur. Reçoit au moment du POST, la valeur saisie dans ce champ.
  • ligne 2 : le champ associé à la balise password du formulaire. Reçoit au moment du POST, la valeur saisie dans ce champ.
  • ligne 13 : associé à la balise textarea du formulaire. Reçoit au moment du POST, le texte saisi dans ce champ.
  • ligne 14 : associé à la balise select1 du formulaire, une liste à choix unique. Sa valeur initiale sélectionne un élément du combo. C'est l'élément ayant son attribut value égal à cette valeur qui sera sélectionnée. Au moment du POST, reçoit l'attribut value de l'option sélectionnée dans le combo.
  • ligne 15 : les chaînes de caractères qui vont alimenter le combo select1.
  • lignes 16 et 17 : idem select1
  • ligne 18 : associé à la balise select1 du formulaire, une liste à choix multiple. Les valeurs initiales dans le tableau sélectionnent les éléments correspondants de la liste. Ce sont les éléments ayant leur attribut value égal à l'un de ces éléments qui seront sélectionnés. Au moment du POST, reçoit les attributs value des différentes options sélectionnées dans le combo.
  • ligne 19 : les chaînes de caractères qui vont alimenter la liste select3
  • ligne 20 : associé à la balise radio du formulaire. Sa valeur sert à cocher l'un des boutons radio, celui qui a son attribut value égal à cette valeur. Reçoit au moment du POST, la valeur du bouton radio coché.
  • ligne 21 : les différents libellés et valeurs des boutons radio.
  • ligne 22 : associé à la balise checkbox du formulaire. Sa valeur initiale sert à cocher / décocher la case. Reçoit au moment du POST, la valeur true si la case a été cochée, false sinon.
  • ligne 23 : associé à la balise checkboxlist du formulaire. Les valeurs initiales dans le tableau sélectionnent les cases à cocher correspondantes. Ce sont les cases ayant leur attribut value égal à l'un de ces valeurs initiales qui seront cochées. Au moment du POST, reçoit les attributs value des différentes cases cochées.
  • ligne 24 : les chaînes de caractères qui vont alimenter les libellés des cases de checkboxlist.
  • ligne 25 : associé au champ caché hidden. Sa valeur initiale va fixer la valeur du champ caché. Au moment du POST, recevra cette même valeur car l'utilisateur n'a pas la possibilité de la modifier.
  • ligne 26 : associé à la balise submit. Au moment du POST, reçoit le libellé du bouton. On peut se passer de ce champ.
  • les méthodes des lignes 29, 34 et 39 seront commentées un peu plus loin.

IX-F. La vue [Form.jsp] - partie Confirmation

La vue [Form.jsp] a une partie " Confirmation des saisies " qui n'a pas encore été vue :

Image non disponible

Son code est le suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
...
    <hr/>
    <h2><s:text name="Confirmation.message"/></h2>
    <table border="1">
      <tr>
        <th><s:text name="Confirmation.champ"/></th>
        <th><s:text name="Confirmation.valeur"/></th>
      </tr>
      <tr>
        <td><s:text name="Form.textfield"/></td>
        <td><s:property value="textfield"/>
      </tr>
      <tr>
        <td><s:text name="Form.password"/></td>
        <td><s:property value="password"/>
      </tr>
      <tr>
        <td><s:text name="Form.textarea"/></td>
        <td><s:property value="textarea"/>
      </tr>
      <tr>
        <td><s:text name="Form.select1"/></td>
        <td><s:property value="select1"/>
      </tr>
      <tr>
        <td><s:text name="Form.select2"/></td>
        <td><s:property value="select2"/>
      </tr>
      <tr>
        <td><s:text name="Form.select3"/></td>
        <td><s:property value="select3SelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.radio"/></td>
        <td><s:property value="radio"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkbox"/></td>
        <td><s:property value="checkbox"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkboxlist"/></td>
        <td><s:property value="checkboxlistSelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.hidden"/></td>
        <td><s:property value="hidden"/>
      </tr>
    </table>
  </body>
</html>
  • ligne 13 : affiche la valeur du champ [Form].textfield
  • ligne 17 : affiche la valeur du champ [Form].password
  • ligne 21 : affiche la valeur du champ [Form].textarea
  • ligne 25 : affiche la valeur du champ [Form].select1
  • ligne 29 : affiche la valeur du champ [Form].select2
  • ligne 33 : affiche les valeurs du tableau [Form].select3. Utilise pour cela, la méthode [Form].getSelect3SelectedValues.
  • ligne 37 : affiche la valeur du champ [Form].radio
  • ligne 41 : affiche la valeur du champ [Form].checkbox
  • ligne 45 : affiche les valeurs du tableau [Form].checkboxlist. Utilise pour cela, la méthode [Form].getCheckboxlistSelectedValues.
  • ligne 49 : affiche la valeur du champ [Form].hidden

IX-G. L'action [Form] - partie confirmation

Les méthodes getSelect3SelectedValues et getCheckboxlistSelectedValues citées précédemment, sont définies dans la classe [Form] :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
  // valeurs sélectionnées dans champ select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  // valeurs sélectionnées dans champ checkboxlist
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // méthode utilitaire
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
}

Elles se contentent de concaténer les éléments des tableaux qu'elles doivent afficher.

IX-H. Les tests

A l'exécution du projet Netbeans, on obtient la page initiale suivante :

Image non disponible

Les valeurs affichées en [1] et [2], proviennent des valeurs initiales des champs de l'action [Form]. Prenons quelques exemples :

 
Sélectionnez
private String textarea = "ligne1\nligne2\n";

La valeur du champ textarea explique les affichages [1A] et [2A].

 
Sélectionnez
private String[] select3 = new String[]{"zéro", "deux"};

private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};

La valeur du champ select3Values explique le contenu de la liste en [1B]. La valeur du champ select3 explique les éléments sélectionnés en [1B] et affichés en [2B].

Si nous saisissons d'autres valeurs dans le formulaire et que nous validons celui-ci, les valeurs saisies vont être postées dans les champs correspondants de l'action [Form]. Puis, la vue [Form.jsp] va être réaffichée. On est donc dans le même cas que précédemment, sauf que les valeurs initiales ont été remplacées par les valeurs postées. Voici un exemple :

Image non disponible

IX-I. L'action [Form1] et la vue [Form1.jsp]

Le fichier de configuration [example.xml] configure l'action [Form1] suivante :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <package name="example" namespace="/example" extends="struts-default">
    <action name="Form" class="example.Form">
      <result name="success">/example/Form.jsp</result>
    </action>
    <action name="Form1" class="example.Form1">
      <result name="success">/example/Form1.jsp</result>
    </action>
    <action name="Form2" class="example.Form2">
      <result name="success">/example/Form2.jsp</result>
    </action>
  </package>
</struts>

Lignes 11-13, l'appel à l'action [Form1] génère la vue [Form1.jsp].

L'action [Form1] est la suivante :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
package example;

import com.opensymphony.xwork2.ActionSupport;

public class Form1 extends ActionSupport{

  // constructeur sans paramètre
  public Form1() {
  }
  // champs du formulaire
  private Data data=new Data();

  /**
   * @return the data
   */
  public Data getData() {
    return data;
  }

  /**
   * @param data the data to set
   */
  public void setData(Data data) {
    this.data = data;
  }
}

L'action [Form1] est identique à l'action [Form] si ce n'est que sa partie modèle a été reléguée dans une classe annexe, la classe [Data], ligne11. La classe [Data] est la suivante :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
package example;

public class Data {

  // constructeur sans paramètre
  public Data() {
  }
  
// champs du formulaire
  private String textfield = "texte";
  private String password = "secret";
  private String textarea = "ligne1\nligne2\n";
  private String select1 = "zéro";
  private String[] select1Values = new String[]{"zéro", "un", "deux"};
  private String select2 = "trois";
  private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
  private String[] select3 = new String[]{"zéro", "deux"};
  private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
  private String radio="bleu";
  private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
  private Boolean checkbox = false;
  private String[] checkboxlist = new String[]{"vélo", "bus"};
  private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
  private String hidden = "initial";
  private String submitText;

  // valeurs sélectionnées dans champ select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  // valeurs sélectionnées dans champ checkboxlist
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // méthode utilitaire
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
  }

  // getters et setters
....

}

On retrouve les champs déclarés précédemment dans l'action [Form].

Assez logiquement, la vue [Form1.jsp] est proche de la vue [Form.jsp] :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title><s:text name="Form.titre"/></title>
    <s:head/>
  </head>

  <body background="<s:url value="/ressources/standard.jpg"/>">
    <h2><s:text name="Form.message"/></h2>
    <h3><s:text name="Form.langues"/></h3>
    <ul>
      <li>
        <s:url id="url" action="Form">
          <s:param name="request_locale">en</s:param>
        </s:url>
        <s:a href="%{url}"><s:text name="Form.anglais"/></s:a>
      </li>
      <li>
        <s:url id="url" action="Form">
          <s:param name="request_locale">fr</s:param>
        </s:url>
        <s:a href="%{url}"><s:text name="Form.francais"/></s:a>
      </li>
    </ul>
    <s:form name="formulaire">
      <s:textfield name="data.textfield" key="Form.textfield" />
      <s:password name="data.password" key="Form.password"/>
      <s:textarea name="data.textarea" key="Form.textarea" cols="40" rows="5"/>
      <s:select name="data.select1" list="data.select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
      <s:select name="data.select2" size="3" list="data.select2Values" key="Form.select2"/>
      <s:select name="data.select3" size="3" list="data.select3Values" key="Form.select3" multiple="true"/>
      <s:radio name="data.radio" list="data.radioValues" key="Form.radio"/>
      <s:checkbox name="data.checkbox" key="Form.checkbox"/>
      <s:checkboxlist name="data.checkboxlist" list="data.checkboxlistValues" key="Form.checkboxlist"/>
      <s:hidden name="data.hidden" key="Form.hidden"/>
      <s:submit key="Form.submitText" name="data.submitText"/>
    </s:form>
    <hr/>
    <h2><s:text name="Confirmation.message"/></h2>
    <table border="1">
      <tr>
        <th><s:text name="Confirmation.champ"/></th>
        <th><s:text name="Confirmation.valeur"/></th>
      </tr>
      <tr>
        <td><s:text name="Form.textfield"/></td>
        <td><s:property value="data.textfield"/>
      </tr>
      <tr>
        <td><s:text name="Form.password"/></td>
        <td><s:property value="data.password"/>
      </tr>
      <tr>
        <td><s:text name="Form.textarea"/></td>
        <td><s:property value="data.textarea"/>
      </tr>
      <tr>
        <td><s:text name="Form.select1"/></td>
        <td><s:property value="data.select1"/>
      </tr>
      <tr>
        <td><s:text name="Form.select2"/></td>
        <td><s:property value="data.select2"/>
      </tr>
      <tr>
        <td><s:text name="Form.select3"/></td>
        <td><s:property value="data.select3SelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.radio"/></td>
        <td><s:property value="data.radio"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkbox"/></td>
        <td><s:property value="data.checkbox"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkboxlist"/></td>
        <td><s:property value="data.checkboxlistSelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.hidden"/></td>
        <td><s:property value="data.hidden"/>
      </tr>
    </table>
  </body>
</html>

La différence entre les vues [Form] et [Form1] peut être illustrée par la ligne 27 reproduite ci-dessous :

 
Sélectionnez
<s:textfield name="data.textfield" key="Form.textfield" />

Le champ de saisie est lié en lecture et écriture au champ data.textfield de l'action [Form1]. On rappelle qu'après exécution, les propriétés de l'action [Form1] sont accessibles à la vue. Ainsi l'attribut name précédent va être évalué comme [Form1].getData().getTextField(). Il faut donc que les deux méthodes get précédentes existent.

IX-J. L'action [Form2] et la vue [Form2.jsp]

Le fichier de configuration [example.xml] configure l'action [Form2] suivante :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <package name="example" namespace="/example" extends="struts-default">
    <action name="Form" class="example.Form">
      <result name="success">/example/Form.jsp</result>
    </action>
    <action name="Form1" class="example.Form1">
      <result name="success">/example/Form1.jsp</result>
    </action>
    <action name="Form2" class="example.Form2">
      <result name="success">/example/Form2.jsp</result>
    </action>
  </package>
</struts>

Lignes 14-16, l'appel à l'action [Form2] génère la vue [Form2.jsp].

L'action [Form2] est la suivante :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
package example;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class Form2 extends ActionSupport implements ModelDriven {

  // constructeur sans paramètre
  public Form2() {
  }
  // modèle de l'action
  public Object getModel() {
    return new Data();
  }
}
  • ligne 6 : l'action [Form2] implémente l'interface [ModelDriven]. Il n'y a qu'une méthode à implémenter, la méthode getModel de la ligne 12. Celle-ci rend une instance de la classe [Data] étudiée précédemment.

Le fait que l'action [Form2] implémente l'interface [ModelDriven] a la conséquence suivante : la vue affichée à la suite de l'action [Form2] a un accès direct aux propriétés du modèle de l'action [Form2], celui-ci étant rendu par la méthode getModel(). aussi la vue [Form2.jsp] redevient ce qu'elle était avec l'action [Form] initiale :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title><s:text name="Form.titre"/></title>
    <s:head/>
  </head>

  <body background="<s:url value="/ressources/standard.jpg"/>">
    <h2><s:text name="Form.message"/></h2>
    <h3><s:text name="Form.langues"/></h3>
    <ul>
      <li>
        <s:url id="url" action="Form">
          <s:param name="request_locale">en</s:param>
        </s:url>
        <s:a href="%{url}"><s:text name="Form.anglais"/></s:a>
      </li>
      <li>
        <s:url id="url" action="Form">
          <s:param name="request_locale">fr</s:param>
        </s:url>
        <s:a href="%{url}"><s:text name="Form.francais"/></s:a>
      </li>
    </ul>
    <s:form name="formulaire">
      <s:textfield name="textfield" key="Form.textfield" />
      <s:password name="password" key="Form.password"/>
      <s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
      <s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<--select 1 -->
      <s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
      <s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
      <s:radio name="radio" list="radioValues" key="Form.radio"/>
      <s:checkbox name="checkbox" key="Form.checkbox"/>
      <s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
      <s:hidden name="hidden" key="Form.hidden"/>
      <s:submit key="Form.submitText" name="submitText"/>
    </s:form>
    <hr/>
    <h2><s:text name="Confirmation.message"/></h2>
    <table border="1">
      <tr>
        <th><s:text name="Confirmation.champ"/></th>
        <th><s:text name="Confirmation.valeur"/></th>
      </tr>
      <tr>
        <td><s:text name="Form.textfield"/></td>
        <td><s:property value="textfield"/>
      </tr>
      <tr>
        <td><s:text name="Form.password"/></td>
        <td><s:property value="password"/>
      </tr>
      <tr>
        <td><s:text name="Form.textarea"/></td>
        <td><s:property value="textarea"/>
      </tr>
      <tr>
        <td><s:text name="Form.select1"/></td>
        <td><s:property value="select1"/>
      </tr>
      <tr>
        <td><s:text name="Form.select2"/></td>
        <td><s:property value="select2"/>
      </tr>
      <tr>
        <td><s:text name="Form.select3"/></td>
        <td><s:property value="select3SelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.radio"/></td>
        <td><s:property value="radio"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkbox"/></td>
        <td><s:property value="checkbox"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkboxlist"/></td>
        <td><s:property value="checkboxlistSelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.hidden"/></td>
        <td><s:property value="hidden"/>
      </tr>
    </table>
  </body>
</html>

Ainsi la ligne 27 qui était précédemment :

 
Sélectionnez
<s:textfield name="data.textfield" key="Form.textfield" />

redevient :

 
Sélectionnez
<s:textfield name="textfield" key="Form.textfield" />

L'avantage de mettre le modèle en-dehors de la vue, est que cette architecture délimite plus clairement les fonctionnalités de chaque élément de l'architecture MVC. Le modèle M est clairement identifié par une classe. Par ailleurs, le modèle peut pré-exister aux actions. Ainsi, si une application web gère une base de personnes, il est probable que la classe Personne existe. Si une action propose un formulaire de saisie pour créer une nouvelle personne, le modèle de cette action est tout trouvé : c'est la classe Personne .

Nous avons vu comme il a été simple de passer de l'action [Form] à l'action [Form2] :

  • le modèle M de la vue V a été encapsulé dans une classe à part
  • l'action qui génère la vue utilisant ce modèle implémente l'interface ModelDriven avec la méthode getModel qui rend une instance du modèle M. L'action peut être alors vue comme une extension du contrôleur C de Struts 2, la classe FilterDispatcher.

Le lecteur pourra appliquer cette démarche à toute action décrite par la suite.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2012 Serge Tahe. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.