Skip to content

9. Esempio 07 – I tag del modulo

Creeremo e utilizzeremo il seguente modulo:

Estenderemo il concetto di iniezione dei parametri, visto in precedenza per un campo di immissione testo, agli altri elementi HTML di un modulo.

9.1. Il progetto NetBeans

  • in [1], le viste del progetto [Formx.JSP]
  • in [2], il file di configurazione di Struts e i messaggi internazionalizzati
  • in [3], le azioni in [Formx.java] e un altro file di configurazione di Struts.

9.2. Configurazione di Struts

Il file [struts.xml] è il seguente:


<?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>
  • riga 9: include un altro file di configurazione [example.xml]. È questo file che configurerà le azioni.
  • righe 11-19: il pacchetto default. Definisce un indirizzo di reindirizzamento per URL /. Verrà reindirizzato a URL /example/Form.action.

Il file [example.xml] che configura le azioni è il seguente:


<?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>
  • righe 7-17: definiscono le azioni /example/Form, /example/Form1, /example/Form2 dove /example è il namespace (riga 7) e Formx le azioni.
  • righe 8-10: l'esecuzione dell'azione Form determinerà la visualizzazione della vista /example/Form.JSP.
  • righe 11-13: l'esecuzione dell'azione Form1 determinerà la visualizzazione della vista /example/Form1.JSP.
  • righe 14-16: l'esecuzione dell'azione Form2 genererà la visualizzazione della vista /example/Form2.JSP.

9.3. I file dei messaggi

Non ci soffermeremo sull’internazionalizzazione del progetto. L’abbiamo già esaminata nell’esempio 01. Riportiamo il contenuto del file [messages.properties] affinché il lettore possa comprendere le viste che seguiranno.


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

9.4. La vista [Form.JSP] – sezione di immissione dati

Il suo aspetto visivo è il seguente:

 

È la seguente:


<%@ 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>
</html>
  • il modulo inizia alla riga 26 e termina alla riga 38. Alla riga 26 manca l'attributo action. Questo attributo specifica a quale azione verranno inviati i dati del modulo. In assenza dell’attributo action, i dati verranno inviati all’azione che ha portato alla visualizzazione della vista, in questo caso l’azione [Form].
  • riga 27: un campo di immissione. L’attributo key ne specifica l’etichetta. L’attributo name è il nome del parametro che verrà inviato. La stringa inviata per questo campo avrà la forma:
textfield=texte_saisi

Il nome del parametro corrisponde a un campo dell’azione [Form]. Il valore del campo di immissione texte_saisi verrà qui inserito nel campo textfield dell’azione [Form]. Viceversa, se la vista [Form.JSP] viene visualizzata a seguito dell’azione [Form], il valore del campo di immissione sarà quello del campo textfield dell’azione [Form]. Questo campo viene quindi utilizzato sia in lettura che in scrittura. A tal fine, la classe [Form] deve disporre dei metodi getTextField e setTextField.

Questo ragionamento vale per tutti i tag di immissione che seguiranno. Non lo ripeteremo.

  • riga 28: inserimento di una password. La stringa inviata all’azione [Form] avrà la forma
password=mot_de_passe_saisi

Nell’azione [Form] deve esistere un campo password con i relativi metodi get e set.

  • riga 29: inserimento di un testo su più righe in un'area di 5 righe e 40 colonne. La stringa inviata all'azione [Form] avrà la forma
textarea=saisie

Nell'azione [Form] deve essere presente un campo textarea con i relativi metodi get e set.

  • riga 30: un menu a tendina (size=1) a selezione singola. È possibile selezionare un solo valore dall’elenco. La stringa inviata all’azione [Form] avrà il formato:
select1=valeur_sélectionnée

Nell’azione [Form] deve essere presente un campo select1 con i relativi metodi get e set.

L'attributo key è l'etichetta dell'elenco. L'attributo list definisce l'elenco dei valori da inserire nel menu a tendina. In questo caso, verrà chiamato il metodo getSelect1Values dell'azione [Form] per popolare il menu a tendina. Questo metodo può restituire una collezione, un dizionario o un array. In questo caso, restituirà un array di stringhe [chaine1, chaine2, ...] che genererà il seguente codice HTML:


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

Il testo tra i tag <option>...</option> verrà visualizzato nel menu a discesa. L’attributo value indica il valore da inviare se l’opzione viene selezionata dall’utente. In questo caso l’attributo value e il testo visualizzato nel menu a discesa sono identici. Nella maggior parte dei casi, però, non è così. Se viene selezionata la seconda opzione, verrà inviata la seguente stringa all’azione [Form]:

select1=chaine2

Il campo [Form].select1 riceverà quindi il valore chaine2. Al contrario, se al momento della visualizzazione del modulo questo campo ha il valore chaine3, allora visivamente il terzo elemento


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

apparirà selezionato nel menu a tendina.

L'attributo headerValue definisce il testo da visualizzare come prima opzione del menu a tendina e headerKey il valore da inviare se tale opzione viene selezionata dall'utente.

  • riga 31: anche in questo caso un elenco di dimensione 3 (size=3): a differenza dell'elenco precedente, in cui è visibile un solo elemento, qui saranno visibili 3 elementi dell'elenco. La modalità di selezione rimane la stessa. È possibile selezionare un solo elemento.
  • riga 32: ancora una volta un elenco, ma con selezione multipla (multiple=true). In questo caso, il valore inviato all’azione [Form] avrà la forma:
select3=chaine2&select3=chaine5

se sono state selezionate le opzioni chaine2 e chaine5. Quando vengono registrati più valori per lo stesso parametro, in questo caso select3, l’azione deve avere un campo con il nome del parametro ed essere di tipo tableau. Quindi, ad esempio, in questo caso l’azione [Form] potrebbe avere un campo del tipo:

String[] select3 ;

e i relativi metodi get / set. L’array select3 riceverà quindi l’array di stringhe [chaine2,chaine5]. Viceversa, durante la visualizzazione della vista [Form.JSP], i valori del campo [Form].select3 determinano le opzioni dell’elenco select3 che appariranno selezionate. Si tratta sempre di operazioni di lettura/scrittura.

  • riga 33: un gruppo di pulsanti di opzione. L'etichetta del gruppo è fornita dall'attributo key. Le etichette dei singoli pulsanti sono fornite dall'attributo list. Il valore di questo attributo è il nome di un metodo dell’azione [Form] che deve restituire una collezione, un dizionario o un array. In questo caso, il metodo [Form].getRadioValues restituirà un array di stringhe [chaine1,chaine2,...] che genererà i seguenti tag HTML:

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

Se il pulsante di opzione chaine2 è selezionato, il valore inviato sarà

radio=chaine2

e tale valore verrà inserito nel campo [Form].radio.

  • riga 34: una casella di selezione. Se è selezionata, verrà inviata la seguente stringa di parametri all’azione [Form]
checkbox=true

Se non è selezionata, non viene inviata alcuna stringa di parametri. Struts 2 dispone di un meccanismo interno che fa sì che tutto avvenga come se la stringa

checkbox=false

fosse stata inviata.

  • riga 35: un elenco di caselle di controllo. È possibile selezionarne più di una. Il testo del gruppo è fornito dall’attributo key. Le etichette delle singole caselle di controllo sono fornite dall'attributo list. Il valore di questo attributo è il nome di un metodo dell'azione [Form] che deve restituire una collezione, un dizionario o un array. In questo caso, il metodo [Form].getCheckboxlistValues restituirà un array di stringhe [chaine1,chaine2,...] che genererà i seguenti tag HTML:

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

Se l'utente seleziona le caselle denominate chaine2 e chaine5, la seguente stringa di caratteri verrà inviata all'azione [Form]:

checkboxlist=chaine2&checkboxlist=chaine5

La tabella [chaine2, chaine5] verrà assegnata al campo [Form].checkboxlist, che deve quindi essere di tipo tabella di stringhe di caratteri, come per gli elenchi a selezione multipla. Viceversa, nella visualizzazione della vista [Form.JSP], i valori del campo [Form].checkboxlist determinano quali caselle di controllo saranno selezionate.

  • riga 36: un campo nascosto. Un campo nascosto è un campo che viene inviato senza essere inserito dall’utente. Il suo valore è fissato dal programmatore. In questo caso il campo nascosto assumerà il valore del campo [Form].hidden. Lo stesso valore verrà inviato nella forma:
hidden=qqchose

e riassegnato al campo [Form].hidden.

  • riga 37: un pulsante di tipo submit. Cliccando su questo pulsante, tutti i valori del modulo verranno inviati all’azione [Form]. La stringa dei parametri inviati sarà simile a questa:
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 

9.5. L'azione [Form] – sezione di inserimento dati

Il suo codice è il seguente:


package example;

import com.opensymphony.xwork2.ActionSupport;

public class Form extends ActionSupport {

  // costruttore senza parametri
  public Form() {
  }
  // campi del modulo
  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;

  // valori selezionati nel campo select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  // valori selezionati nel campo checkboxlist
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // metodo di utilità
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
  }

// getter e setter dei campi
  ....
}
  • riga 1: il campo associato al tag textfield del modulo. Servirà sia per inizializzare questo campo di immissione dati sia per recuperarne il valore. Riceve, al momento dell’esecuzione di POST, il valore inserito in questo campo.
  • riga 2: il campo associato al tag password del modulo. Al momento dell’esecuzione di POST, riceve il valore inserito in questo campo.
  • riga 13: associata al tag textarea del modulo. Al momento del POST, riceve il testo inserito in questo campo.
  • riga 14: associata al tag select1 del modulo, un elenco a scelta singola. Il suo valore iniziale seleziona un elemento del menu a tendina. Verrà selezionato l'elemento il cui attributo value è uguale a tale valore. Al momento dell’esecuzione di POST, riceve l’attributo value dell’opzione selezionata nel menu a discesa.
  • riga 15: le stringhe di caratteri che andranno ad alimentare il menu a tendina select1.
  • righe 16 e 17: idem select1
  • riga 18: associato al tag select1 del modulo, un elenco a scelta multipla. I valori iniziali nella tabella selezionano gli elementi corrispondenti dell’elenco. Verranno selezionati gli elementi il cui attributo value è uguale a uno di questi elementi. Al momento dell’esecuzione di POST, riceve gli attributi value delle diverse opzioni selezionate nel menu a tendina.
  • riga 19: le stringhe di caratteri che andranno ad alimentare l’elenco select3
  • riga 20: associata al tag radio del modulo. Il suo valore serve a selezionare uno dei pulsanti di opzione, ovvero quello il cui attributo value è uguale a questo valore. Al momento dell’esecuzione di POST, riceve il valore del pulsante di opzione selezionato.
  • riga 21: le diverse etichette e i valori dei pulsanti di opzione.
  • riga 22: associata al tag checkbox del modulo. Il suo valore iniziale serve a selezionare/deselezionare la casella. Al momento dell’evento POST, riceve il valore true se la casella è stata selezionata, false in caso contrario.
  • riga 23: associata al tag checkboxlist del modulo. I valori iniziali nella tabella selezionano le caselle di controllo corrispondenti. Saranno selezionate le caselle il cui attributo value è uguale a uno di questi valori iniziali. Al momento dell’esecuzione di POST, riceve gli attributi value delle diverse caselle selezionate.
  • riga 24: le stringhe di caratteri che andranno a popolare le etichette delle caselle di checkboxlist.
  • riga 25: associata al campo nascosto hidden. Il suo valore iniziale determinerà il valore del campo nascosto. Al momento dell’aggiornamento POST, riceverà lo stesso valore poiché l’utente non ha la possibilità di modificarlo.
  • riga 26: associata al tag submit. Al momento dell’esecuzione di POST, riceve l’etichetta del pulsante. È possibile fare a meno di questo campo.
  • I metodi delle righe 29, 34 e 39 saranno commentati più avanti.

9.6. La vista [Form.JSP] – sezione Conferma

La vista [Form.JSP] presenta una sezione «Conferma dei dati inseriti» che non è stata ancora esaminata:

 

Il suo codice è il seguente:


<%@ 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>
  • riga 13: visualizza il valore del campo [Form].textfield
  • riga 17: visualizza il valore del campo [Form].password
  • riga 21: visualizza il valore del campo [Form].textarea
  • riga 25: visualizza il valore del campo [Form].select1
  • riga 29: visualizza il valore del campo [Form].select2
  • riga 33: visualizza i valori della tabella [Form].select3. A tal fine, utilizza il metodo [Form].getSelect3SelectedValues.
  • riga 37: visualizza il valore del campo [Form].radio
  • riga 41: visualizza il valore del campo [Form].checkbox
  • riga 45: visualizza i valori dell’array [Form].checkboxlist. A tal fine, utilizza il metodo [Form].getCheckboxlistSelectedValues.
  • riga 49: visualizza il valore del campo [Form].hidden

9.7. L'azione [Form] – parte di conferma

I metodi getSelect3SelectedValues e getCheckboxlistSelectedValues citati in precedenza sono definiti nella classe [Form]:


  // valori selezionati nel campo select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  // valori selezionati nel campo checkboxlist
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // metodo di utilità
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
}

Si limitano a concatenare gli elementi delle tabelle che devono visualizzare.

9.8. I test

All'esecuzione del progetto NetBeans, si ottiene la seguente pagina iniziale:

I valori visualizzati in [1] e [2] provengono dai valori iniziali dei campi dell’azione [Form]. Vediamo alcuni esempi:


private String textarea = "ligne1\nligne2\n";

Il valore del campo textarea spiega i valori visualizzati in [1A] e [2A].


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

Il valore del campo select3Values spiega il contenuto dell'elenco in [1B]. Il valore del campo select3 descrive gli elementi selezionati in [1B] e visualizzati in [2B].

Se inseriamo altri valori nel modulo e lo convalidiamo, i valori inseriti verranno inviati ai campi corrispondenti dell'azione [Form]. Successivamente, verrà nuovamente visualizzata la vista [Form.JSP]. Ci troviamo quindi nella stessa situazione di prima, tranne per il fatto che i valori iniziali sono stati sostituiti da quelli inviati. Ecco un esempio:

9.9. L'azione [Form1] e la vista [Form1.JSP]

Il file di configurazione [example.xml] configura la seguente azione [Form1]:


<?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>

Alle righe 11-13, la chiamata all'azione [Form1] genera la vista [Form1.JSP].

L'azione [Form1] è la seguente:


package example;

import com.opensymphony.xwork2.ActionSupport;

public class Form1 extends ActionSupport{

  // costruttore senza parametri
  public Form1() {
  }
  // campi del modulo
  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'azione [Form1] è identica all'azione [Form], tranne per il fatto che la sua parte relativa al modello è stata trasferita in una classe secondaria, la classe [Data], riga 11. La classe [Data] è la seguente:


package example;

public class Data {

  // costruttore senza parametri
  public Data() {
  }
  
// campi del modulo
  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;

  // valori selezionati nel campo select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  // valori selezionati nel campo checkboxlist
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // metodo di utilità
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
  }

  // getter e setter
....

}

Si ritrovano i campi dichiarati in precedenza nell’azione [Form].

Com'era prevedibile, la vista [Form1.JSP] è simile alla vista [Form.JSP]:


<%@ 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 differenza tra le viste [Form] e [Form1] può essere illustrata dalla riga 27 riportata di seguito:


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

Il campo di immissione è collegato in lettura e scrittura al campo data.textfield dell’azione [Form1]. Si ricorda che, dopo l’esecuzione, le proprietà dell’azione [Form1] sono accessibili alla vista. Pertanto, l'attributo name precedente verrà valutato come [Form1].getData().getTextField(). È quindi necessario che i due metodi get precedenti esistano.

9.10. L’azione [Form2] e la vista [Form2.JSP]

Il file di configurazione [example.xml] configura la seguente azione [Form2]:


<?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>

Alle righe 14-16, la chiamata all’azione [Form2] genera la vista [Form2.JSP].

L'azione [Form2] è la seguente:


package example;

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

public class Form2 extends ActionSupport implements ModelDriven {

  // costruttore senza parametri
  public Form2() {
  }
  // modello dell'azione
  public Object getModel() {
    return new Data();
  }
}
  • riga 6: l'azione [Form2] implementa l'interfaccia [ModelDriven]. C'è un solo metodo da implementare, il metodo getModel alla riga 12. Questo restituisce un'istanza della classe [Data] esaminata in precedenza.

Il fatto che l’azione [Form2] implementi l’interfaccia [ModelDriven] comporta quanto segue: la vista visualizzata a seguito dell’azione [Form2] ha accesso diretto alle proprietà del modello dell’azione [Form2], poiché quest’ultimo viene restituito dal metodo getModel(). Pertanto, la vista [Form2.JSP] torna ad essere quella che era con l'azione iniziale [Form]:


<%@ 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/>
    <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>

Pertanto, la riga 27, che in precedenza era:


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

torna ad essere:


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

Il vantaggio di collocare il modello al di fuori della vista è che questa architettura delimita più chiaramente le funzionalità di ciascun elemento dell'architettura MVC. Il modello M è chiaramente identificato da una classe. Inoltre, il modello può preesistere alle azioni. Pertanto, se un’applicazione web gestisce un database di persone, è probabile che la classe Personne esista già. Se un’azione propone un modulo di inserimento dati per creare una nuova persona, il modello di tale azione è già pronto: si tratta della classe Personne.

Abbiamo visto quanto sia stato semplice passare dall’azione [Form] all’azione [Form2]:

  • il modello M della vista V è stato incapsulato in una classe separata
  • l'azione che genera la vista utilizzando questo modello implementa l'interfaccia ModelDriven con il metodo getModel che restituisce un'istanza del modello M. L'azione può quindi essere vista come un'estensione del controller C di Struts 2, la classe FilterDispatcher.

Il lettore potrà applicare questo approccio a qualsiasi azione descritta di seguito.