Skip to content

6. Moduli HTML

Finora abbiamo utilizzato un unico modulo composto da soli due campi di immissione dati. In questa sede ci proponiamo di creare e gestire un modulo utilizzando i componenti grafici più comuni (pulsanti di opzione, caselle di controllo, campi di immissione dati, caselle a discesa, elenchi).

6.1. Le viste dell’applicazione

L’applicazione avrà solo due viste. La prima presenta un modulo vuoto:

QZXW2HTMLP000547ZQX 1 - formulaire

Image

Questa prima vista, denominata formulaire.jsp, ci consentirà di implementare diversi tag della libreria struts-html. L’utente compila il modulo:

Image

Il pulsante [Envoyer] consente di ottenere una conferma dei valori inseriti. Questa sarà la seconda vista:

Image

Questa seconda vista ci consentirà di utilizzare altre due librerie di tag: struts-bean e struts-logic. Il link [Retour au formulaire] ci permette di tornare al modulo così come è stato compilato. Si torna quindi alla prima vista.

6.2. L’architettura dell’applicazione

  • Il modulo (vista 1) sarà rappresentato da un oggetto Struts dinamico denominato dynaFormulaire, di tipo derivato da DynaActionForm. Verrà visualizzato dalla vista formulaire.jsp.
  • L’azione Struts InitFormulaireAction avrà lo scopo di acquisire i dati necessari per la visualizzazione del modulo
  • il modulo compilato verrà elaborato dall’azione ForwardAction, che si limiterà a reindirizzare la richiesta alla seconda vista confirmation.jsp. Quest’ultima si occuperà di visualizzare i valori del modulo.

6.3. La configurazione dell’applicazione

6.3.1. Il file server.xml

Il contesto dell’applicazione si chiamerà /formulaire2. Aggiungeremo quindi la seguente riga nel file server.xml di Tomcat:

    <Context path="/formulaire2" docBase="e:/data/serge/web/struts/formulaire2" />

Fatto ciò, se necessario, riavviamo Tomcat affinché riconosca il nuovo contesto. Possiamo verificarne la validità richiedendo l’URL http://localhost:8080/formulaire2:

Image

6.3.2. Il file web.xml

Il file di configurazione web.xml dell’applicazione sarà il seguente:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <servlet>
      <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
      <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
  </taglib>

</web-app>

Rispetto ai file di configurazione web.xml già incontrati, apportiamo alcune modifiche:

  • introduciamo due nuove librerie di tag: struts-bean e struts-logic. Queste saranno utilizzate nella vista confirmation.jsp. La vista formulaire.jsp utilizzerà invece la libreria struts-html.

6.3.3. Il file struts-config.xml

Il file struts-config.xml sarà invece il seguente:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
    <form-beans>
        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                  
        </form-bean>            
    </form-beans>

    <action-mappings>
      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

    </action-mappings>

        <message-resources 
      parameter="ApplicationResources"
        null="false"/>    

</struts-config>

Qui si trovano le tre sezioni principali:

  • la dichiarazione dei moduli nella sezione <form-beans>
  • la dichiarazione delle azioni nella sezione <action-mappings>
  • la dichiarazione del file delle risorse nella sezione <message-ressources>

6.3.4. Gli oggetti (bean) dei moduli dell'applicazione

Gli oggetti utilizzati per rappresentare i moduli HTML dell'applicazione sono oggetti di tipo ActionForm o derivati (DynaActionForm, DynaValidatorForm, ...). Vengono chiamati bean perché la loro struttura segue le regole dei JavaBeans. Nella nostra applicazione è presente un solo bean del modulo, denominato dynaFormulaire e di tipo derivato da DynaActionForm. Verrà utilizzato nelle seguenti situazioni:

  • contenere i dati necessari per la visualizzazione della vista n. 1
  • recuperare i valori del modulo della vista n. 1 quando l’utente lo invia (submit)
  • contenere i dati necessari per la visualizzazione della vista n. 2

La struttura del bean dynaFormulaire è strettamente legata al modulo della vista n. 1. Esaminiamolo:

N.
Tipo HTML
Ruolo
1
<input name="opt" type="radio" value="sì">
<input name="opt" type="radio" value="no">
gruppo di pulsanti di opzione collegati tra loro (stesso nome)
2
<input name="chk1" type="radio" value="on">
<input name="chk2" type="radio" value="on">
<input name="chk3" type="radio" value="on">
gruppi di caselle di controllo
indipendenti (non hanno lo stesso nome)
3
<input type="text" name="champSaisie" >
un campo di immissione
4
<input type="password" name="mdp">
un campo password
5
<textarea name="boiteSaisie">...</textarea>
un campo di immissione multilinea
6
<select name="combo" size="1">..</select>
un menu a tendina
7
<select name="listeSimple" size="3">..</select>
un elenco a selezione singola
8
<select name="listeMultiple" size="3" multiple>..</select>
un elenco a selezione multipla
9
<input type="button" value="Cancella"
onclick='effacerListe("listeSimple")'>
pulsante che consente di deselezionare
gli elementi selezionati in listeSimple (7)
10
<input type="button" value="Cancella"
onclick='effacerListe("listeMultiple")'>
pulsante che consente di deselezionare
gli elementi selezionati in listeMultiple (8)
11
<input type="submit" value="Invia">
pulsante di invio del modulo
12
<input type="hidden" name="secret" value="...">
un campo nascosto

Distinguiamo diversi casi:

  1. l'oggetto dynaFormulaire viene utilizzato per contenere i valori del modulo HTML sopra riportato, che verrà inviato tramite il pulsante [Envoyer]. Deve quindi avere gli stessi campi presenti nel modulo HTML. Il tipo di campo è determinato dalla seguente regola:
  • se il campo HTML fornisce un solo valore, allora il campo di dynaFormulaire sarà di tipo java.lang.String
  • se il campo HTML fornisce più valori, allora il campo di dynaFormulaire sarà di tipo java.lang.String[]

Nel modulo HTML sopra riportato, solo il campo listeMultiple può essere associato a più valori (quelli selezionati dall’utente). Pertanto, una prima definizione dell’oggetto dynaFormulaire sarebbe la seguente:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
        </form-bean>            

Come avverrà il popolamento di dynaFormulaire con i valori del modulo HTML inviati dal client web?

opt
il campo «opt» riceverà il valore «sì» se è stato selezionato il campo HTML <input type="radio" name="opt" value="sì">, il valore «no» se è stato selezionato il campo <input type="radio" name="opt" value="no">.
chk1
il campo chk1 assumerà il valore "on" se è stato selezionato il campo HTML <input name="chk1" type="radio" value="1">, altrimenti non assumerà alcun valore. In quest’ultimo caso, il campo chk1 manterrà il suo valore precedente.
chk2
idem
chk3
idem
champSaisie
il campo champSaisie riceverà il testo inserito dall'utente nel campo HTML <input type="text" name="champSaisie">. Tale testo può eventualmente essere una stringa vuota.
mdp
il campo mdp riceverà il testo inserito dall'utente nel campo HTML <input type="password" name="mdp">. Tale testo può eventualmente essere una stringa vuota.
boiteSaisie
Il campo boiteSaisie riceverà il testo inserito dall'utente nel campo HTML <textarea name="boiteSaisie">...</textarea>. Questo testo costituisce un'unica stringa di caratteri, formata dalle righe digitate dall'utente e separate l'una dall'altra dalla sequenza di caratteri "\r\n". Il testo ottenuto può eventualmente essere una stringa vuota.
combo
il campo a discesa riceverà l’opzione selezionata dall’utente nel campo HTML <select name="combo" size="1">..</select>. L’opzione selezionata è quella che appare nel campo a discesa. Se l’opzione HTML selezionata è del tipo <option value="XX">YY</option>, il campo a discesa riceverà il valore "XX". Se l’opzione HTML selezionata è del tipo <option>YY</option>, il campo a discesa riceverà il valore "YY".
listeSimple
il campo listeSimple riceverà l’opzione selezionata dall’utente nel campo HTML <select name="listeSimple" size="..">..</select> se presente. Se non ce n’è nessuna, il campo listeSimple non riceverà alcun valore e manterrà il valore precedente. Il valore effettivamente assegnato al campo listeSimple segue le regole indicate per il menu a tendina.
listeMultiple
il campo listeMultiple di tipo String[] riceverà le opzioni selezionate dall’utente nel campo HTML <select name="listeMultiple" size=".." multiple>..</select> se presenti. Se non ce ne sono, l'array listeMultiple non riceverà alcun valore e il suo contenuto rimarrà invariato. I valori effettivamente assegnati all'array listeMultiple seguono le regole indicate per il menu a tendina.
secret
il campo «secret» riceverà il valore XX dal campo HTML <input type="hidden" name="secret" value="XX">. Questo testo può eventualmente essere una stringa vuota.
  1. L'oggetto dynaFormulaire viene utilizzato per fornire il contenuto iniziale della vista n. 1. I valori dei campi precedenti saranno utilizzati per i seguenti scopi:
opt
dovrà avere il valore "" o "no" affinché il browser sappia quale pulsante di opzione selezionare
chk1
se chk1 ha il valore "on", la casella di controllo sarà selezionata, altrimenti non lo sarà
chk2
idem
chk3
idem
champSaisie
il valore del campo verrà visualizzato nell'area di immissione champSaisie
mdp
il valore del campo verrà visualizzato nel campo di immissione password
boiteSaisie
il valore del campo verrà visualizzato nel campo di immissione boiteSaisie
combo
il valore di questo campo indica quale elemento del menu a tendina deve essere selezionato alla visualizzazione del modulo
listeSimple
idem
listeMultiple
i valori della tabella listeMultiple indicano quali elementi dell'elenco multiplo devono essere selezionati al momento della visualizzazione del modulo
secret
il valore del campo verrà assegnato all'attributo "value" del campo segreto HTML.

La vista n. 1 richiede ulteriori informazioni:

  • l’elenco dei valori da visualizzare nell’elenco a discesa
  • l'elenco dei valori da visualizzare nell'elenco listeSimple
  • l'elenco dei valori da visualizzare nell'elenco listeMultiple

Esistono diversi modi per fornire queste informazioni alla vista. Ad esempio, potrebbero andare bene delle tabelle inserite nella query passata alla vista. In questo caso, inseriamo queste tabelle nel bean dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                  
        </form-bean>            

Il modulo dynaFormulaire verrà inizializzato dall'azione /init, che richiamerà un oggetto derivato da Action denominato InitFormulaireAction. Sarà questo oggetto a occuparsi di creare i tre array necessari per la visualizzazione dei tre elenchi e di inserirli nel bean dynaFormulaire. Il file di configurazione assegna a questo bean un ambito pari alla sessione. Ciò comporta che il controller Struts inserirà questo bean nella sessione. In questo modo non sarà necessario rigenerarlo tra un ciclo richiesta-risposta e l’altro. Pertanto, l’azione /init verrà chiamata una sola volta.

  1. L’oggetto dynaFormulaire viene utilizzato anche per fornire il contenuto della vista n. 2. Quest’ultima si limita a visualizzarne i valori.

6.3.5. Le azioni dell’applicazione

Le azioni sono gestite da oggetti di tipo Action o derivati. La configurazione delle azioni avviene all’interno dei tag <action-mappings>:

    <action-mappings>
      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

    </action-mappings>

Si noti che non sempre a un'azione è associato un modulo. È il caso, nell'esempio sopra riportato, dell'azione /affiche. Prima di descrivere in dettaglio ciascuna azione, ricordiamo il funzionamento della coppia azione-modulo associata all'interno di un tag <action>:

  • un'azione inizia con una richiesta da parte di un client web e termina con l'invio di una pagina di risposta. Si tratta del ciclo richiesta-risposta del client-server web. La richiesta viene ricevuta dal controller Struts di tipo ActionServlet o derivato. È lo stesso controller che invia la risposta.
  • Il bean del modulo di tipo ActionForm o derivato viene creato se non esiste già. Il controller verifica se riesce a trovare un oggetto con il nome name nell’ambito indicato da scope. In caso affermativo, lo utilizza. In caso contrario, lo crea e lo inserisce nell’ambito indicato da scope, associandolo all’attributo indicato da name.

Nell’esempio dell’azione /init, ad esempio, il controller eseguirà un request.getSession().getAttribute("dynaFormulaire") per verificare se dynaFormulaire sia già stato creato o meno. Se così non fosse, lo creerà e lo inserirà nella sessione tramite un’istruzione del tipo request.getSession().setAttribute("dynaFormulaire", new DynaFormulaire(...)).

  • Il controller cercherà inoltre un oggetto Action del tipo indicato dall’attributo type. Se non lo trova, lo crea; altrimenti lo utilizza.
  • Verrà chiamato il metodo reset del bean del modulo. Quest’ultimo, tranne che al momento della sua creazione iniziale, viene riciclato. Contiene quindi dati che si potrebbe voler “ripulire”. È nel metodo reset del bean ActionForm o derivato che si effettuerà questa operazione.
  • Se l'azione è la destinazione di un modulo inviato tramite POST, i valori del modulo presenti nella richiesta del client vengono copiati nei campi con lo stesso nome del bean del modulo. Si noti che il metodo reset è stato chiamato prima di questa copia.
  • Se la configurazione specifica l'attributo `validate="true"`, verrà chiamato il metodo `validate` del bean del modulo. Quest'ultimo dovrà quindi verificare i dati del bean. Questa verifica avviene solitamente solo quando il modulo ha appena ricevuto nuovi dati tramite un form inviato con il metodo POST e si desidera verificarne la validità. Questo metodo restituisce al controller un eventuale elenco di errori in un oggetto ActionErrors.
  • Se l’oggetto ActionErrors non è vuoto, il controller fa visualizzare la vista specificata dall’attributo input dell’azione.
  • Se la convalida dei dati non è richiesta o se è stata eseguita con successo, il controller fa eseguire il metodo `execute` dell’oggetto di tipo `Action` o derivato associato all’azione in corso. È all’interno di questo metodo che viene elaborata la richiesta del client web. Il metodo `execute` restituisce un oggetto ActionForward indicizzato da chiavi di tipo stringa di caratteri. Queste chiavi sono quelle dichiarate dai tag forward dell’azione configurata. Nel nostro esempio, l’azione /init ha un unico tag forward. Essa associa la chiave "afficherFormulaire" alla vista formulaire.jsp.
  • il controller fa visualizzare la vista a cui è associata la chiave ricevuta. Questa vista può essere a sua volta un'azione, nel qual caso il processo precedente viene ripetuto.

L'azione /init

        <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>
  • L'azione /init avviene normalmente una volta durante il primo ciclo richiesta-risposta quando l'utente richiede l'http://localhost:8080/formulaire2/init.do URL
  • viene creato o riciclato l’oggetto dynaFormulaire. Esso viene recuperato (riciclaggio) o inserito (creazione) nella sessione come richiesto dall’attributo scope.
  • Viene chiamato il suo metodo reset. Cosa deve fare? Normalmente, i campi dell’oggetto ActionForm vengono reimpostati ai valori predefiniti. Solo che in questo caso non lo faremo, poiché l’oggetto dynaFormulaire viene inserito nella sessione (scope="session"). I campi di dynaFormulaire devono quindi mantenere i propri valori. Quali sono questi valori al momento della creazione iniziale dell’oggetto dynaFormulaire? Esistono due casi:
  • il campo ha un valore iniziale specificato nel file di configurazione:
            <form-property name="opt" type="java.lang.String" initial="non"/>

In questo caso, il controller Struts creerà questo campo con tale valore iniziale.

  • il campo non ha un valore iniziale specificato nella configurazione: si applicano le regole di inizializzazione di Java. In generale, i campi numerici avranno il valore zero, le stringhe di caratteri avranno come valore la stringa vuota, mentre gli altri oggetti avranno il valore null.

Esaminiamo la configurazione iniziale di dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>             
        </form-bean>            

I valori iniziali dei campi di dynaFormulaire dopo la sua creazione saranno i seguenti:

Campo
Valore iniziale
opt
"no"
chk1, chk2, chk3
stringa vuota
champSaisie
stringa vuota
mdp
stringa vuota
boiteSaisie
stringa vuota
combo
stringa vuota
listeSimple
stringa vuota
listeMultiple
tabella di stringhe vuote
secret
"xxx"
valeursCombo, listeSimple, listeMultiple
array di stringhe vuote
  • si potrebbe immaginare che il metodo reset di dynaFormulaire assegni dei valori ai tre array destinati ad alimentare le tre liste della vista formulaire.jsp. Ciò sarebbe possibile in questo caso poiché i dati di questi tre array vengono generati in modo arbitrario. Tuttavia, il caso più comune è che tali dati provengano dal modello dell’applicazione, ovvero l’M di MVC. In questo caso, per non complicare l’esempio, adotteremo una posizione intermedia, facendo generare questi valori dall’azione InitFormulaireAction, ovvero dal C di MVC.
  • Non è obbligatorio scrivere un metodo reset in dynaFormulaire, poiché la classe ActionForm da cui deriva dispone già di un metodo di questo tipo che non esegue alcuna operazione (nessuna inizializzazione).
  • Una volta chiamato il metodo reset di dynaFormulaire, il controller controlla l’attributo validate dell’azione. In questo caso, il valore è "false". Il metodo validate di dynaFormulaire non verrà chiamato.
  • L’oggetto InitFormulaireAction viene creato o riciclato se già esistente e viene eseguito il suo metodo `execute`. È proprio questo metodo che assegnerà valori arbitrari ai tre array di dynaFormulaire: valeursCombo, valeursListeSimple e valeursListeMultiple. Il metodo restituisce un ActionForward con chiave "afficherFormulaire".
  • Il controller visualizza la vista /vues/formulaire.jsp, che è stata associata alla chiave "afficherFormulaire" tramite un tag forward dell'azione /init.

L'azione /confirmation

      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • L'azione /confirmation viene eseguita quando l'utente preme il pulsante [Envoyer] nella vista n. 1. Il browser "invia" quindi al controller Struts il modulo compilato dall'utente.
  • L'oggetto dynaFormulaire viene inserito nella sessione
  • viene chiamato il suo metodo reset. Una volta chiamato, il controller Struts copierà i valori dei campi del modulo inviato dal client nei campi con lo stesso nome di dynaFormulaire. Riprendiamo l’elenco dei campi di quest’ultimo e vediamo come avviene questa copia:
Campo
Codice HTML associato
Valore del campo
dopo il trasferimento dei valori del modulo
opt
<input type="radio" name="opt" value="sì">Sì
<input type="radio" name="opt" value="no" checked="checked">No
- "sì" o "no" a seconda del pulsante di opzione selezionato
chk1
<input type="checkbox" name="chk1" value="on">
- "on" se la casella chk1 è stata selezionata
- mantiene il valore precedente se la casella chk1 non è stata spuntata
chk2
<input type="checkbox" name="chk2" value="on">
- "on" se la casella chk2 è stata selezionata
- mantiene il valore precedente se la casella chk2 non è stata selezionata
chk3
<input type="checkbox" name="chk2" value="on">
- "on" se la casella chk3 è stata selezionata
- mantiene il valore precedente se la casella chk3 non è stata selezionata
champSaisie
<input type="text" name="champSaisie" value="">
- valore digitato dall'utente in champSaisie
mdp
<input type="password" name="mdp" value="">
- valore digitato dall'utente in mdp
boiteSaisie
<textarea name="boiteSaisie"></textarea>
- valore digitato dall'utente in boiteSaisie
combo
<select name="combo">...</select>
- valore selezionato dall'utente in combo
listeSimple
<select name="listeSimple" size="3">...</select>
- valore selezionato dall'utente in listeSimple
listeMultiple
<select name="listeMultiple" multiple="multiple" size="5">
- array di stringhe contenente i valori selezionati dall'utente in listeMultiple
secret
<input type="hidden" name="secret" value="xxx">
- "xxx".

Si riscontra una difficoltà con i campi che non ricevono necessariamente un valore nella richiesta inviata dal browser. È il caso delle caselle di controllo da chk1 a chk3 e dei due elenchi listeSimple e listeMultiple. In questo caso, tali campi mantengono il loro valore precedente, ovvero quello acquisito durante il ciclo richiesta-risposta precedente.

Prendiamo ad esempio la casella di controllo chk1 e supponiamo che nel precedente ciclo richiesta-risposta l’utente avesse spuntato questa casella. Il browser aveva quindi inviato nella stringa dei parametri della sua richiesta l’informazione chk1="on". Il costruttore ha quindi assegnato il valore "on" al campo chk1 di dynaFormulaire. Supponiamo ora che nel ciclo in corso l’utente non selezioni la casella chk1. In questo caso, nella stringa dei parametri della nuova richiesta, il browser non invia qualcosa come chk1="off", ma non invia nulla. Di conseguenza, il campo chk1 di dynaFormulaire manterrà il valore "on" e quindi avrà un valore che non riflette quello del modulo convalidato dall’utente. Per risolvere questo problema useremo il metodo reset di dynaFormulaire. In questo metodo imposteremo i tre campi chk1, chk2, chk3 su "off". Nel nostro esempio relativo a chk1, supponiamo che l’utente:

  • spunta la casella chk1. In tal caso, il browser invia l’informazione chk1="on" e il campo chk1 di dynaFormulaire passerà a "on"
  • non seleziona la casella chk1. In tal caso, il browser non invia alcun valore per il campo chk1, che manterrà il suo valore precedente "off". In entrambi i casi, il valore registrato nel campo chk1 di dynaFormulaire è corretto.

Il problema è analogo per entrambi gli elenchi listeSimple e listeMultiple. Se in questi elenchi non è stata selezionata alcuna opzione, esse non saranno presenti nei parametri della query e manterranno quindi i loro valori precedenti. Nel metodo reset di dynaFormulaire, reinizializzeremo listeSimple con una stringa vuota e listeMultiple con un array di stringhe di lunghezza 0.

  • Una volta chiamato il metodo reset di dynaFormulaire, il controller ricopia nei campi di dynaFormulaire le informazioni che gli sono state inviate nella richiesta del cliente
  • Viene creato o riciclato un oggetto ForwardAction e viene chiamato il suo metodo `execute`. ForwardAction è una classe predefinita che restituisce un oggetto ActionForward che punta alla vista definita dall'attributo "parameter" dell'azione, in questo caso /vues/confirmation.jsp.
  • Il controller invia questa vista. Il ciclo è completato.

L'azione /visualizza

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • L'azione /affiche viene attivata cliccando sul link [Retour vers le formulaire] della vista n. 2.
  • In questo caso non vi è alcun modulo associato all’azione. Si passa quindi immediatamente all’esecuzione del metodo `execute` di un oggetto `ForwardAction`, che restituirà un oggetto `ActionForward` che punta alla vista `/vues/formulaire.jsp`.

6.3.6. Il file dei messaggi dell’applicazione

La terza sezione del file struts-config.xml è quella del file dei messaggi:

        <message-resources 
          parameter="ApplicationResources"
            null="false"
      />    

Il file ApplicationResources.properties si trova nella cartella WEB-INF/classes. Sarà vuoto. Anche se vuoto, deve comunque essere dichiarato nel file di configurazione, altrimenti la libreria di tag struts-bean, di cui parleremo più avanti, genererà un errore. Questa libreria è utilizzata dalla vista confirmation.jsp.

6.4. Il codice delle viste

6.4.1. La vista formulaire.jsp

Ricordiamo che questa vista viene visualizzata in due casi:

  • quando viene chiamata l’azione /init durante il primo ciclo richiesta-risposta
  • all'invocazione dell'azione /affiche nei cicli successivi

Il codice della vista formulaire.jsp è il seguente:

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html>
  <head>
      <title>formulaire</title>
  </head>  
  <body background='<html:rewrite page="/images/standard.jpg"/>'>
      <h3>Formulaire Struts</h3>
    <hr>
    <html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
      <table border="0">
        <tr>
          <td>bouton radio</td>
          <td>
                        <html:radio name="dynaFormulaire" property="opt" value="oui">Oui</html:radio>
                        <html:radio name="dynaFormulaire" property="opt" value="non">Non</html:radio>                                            
          </td>
        </tr>
        <tr>
          <td>Cases à cocher</td>
          <td>
                        <html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
                        <html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
                        <html:checkbox name="dynaFormulaire" property="chk3">3</html:checkbox>                                                
          </td>
        </tr>
        <tr>
          <td>Champ de saisie</td>
          <td>
                        <html:text name="dynaFormulaire" property="champSaisie" />
          </td>
        </tr>
        <tr>
          <td>Mot de passe</td>
          <td>
              <html:password name="dynaFormulaire" property="mdp" />
          </td>
        </tr>
        <tr>
          <td>Boîte de saisie multilignes</td>
          <td>
              <html:textarea name="dynaFormulaire" property="boiteSaisie" />
          </td>
        </tr>
        <tr>
          <td>Combo</td>
          <td>
              <html:select name="dynaFormulaire" property="combo">
                            <html:options name="dynaFormulaire" property="valeursCombo"/>
                        </html:select>
          </td>
        </tr>
        <tr>
          <td>
                        <table>
                            <tr>
                                <td>Liste à sélection unique</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>
                                </td>
                            </tr>
                        </table>
          <td>
              <html:select name="dynaFormulaire" property="listeSimple" size="3">
                            <html:options name="dynaFormulaire" property="valeursListeSimple"/>                        
                        </html:select>
          </td>
        </tr>
        <tr>
                    <td>
                        <table>
                            <tr>
                                <td>Liste à sélection multiple</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>                                
                                </td>
                            </tr>
                        </table>
                    </td>
          <td>
              <html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
                            <html:options name="dynaFormulaire" property="valeursListeMultiple"/>                        
                        </html:select>
          </td>
        </tr>
      </table>
      <html:hidden name="dynaFormulaire" property="secret"/>
            <br>
            <hr>
            <html:submit>Envoyer</html:submit> 
    </html:form>
  </body>
</html>

Questa pagina JSP utilizza tag provenienti dalla libreria struts-html. Ricordiamo che per utilizzare una libreria di tag è necessario:

  • dichiararla nel file web.xml dell'applicazione con un tag <tag-lib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  • inserire il codice di questa libreria in una posizione qualsiasi nella struttura dell'applicazione, in questo caso WEB-INF/struts-html.tld
  • Dichiarare l'utilizzo di questa libreria all'inizio delle pagine JSP che la utilizzano:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

La vista formulaire.jsp utilizza dei tag che spieghiamo ora:

balise
<body background="<html:rewrite page="/images/standard.jpg"/>">
traduction HTML
<body background="/formulaire2/images/standard.jpg">
explication
Il tag html:rewrite consente di prescindere dal nome dell'applicazione in URL. Ha un attributo:
page
URL da riscrivere
Quindi, come sopra, se si decide di chiamare l'applicazione "formulaire3", il codice dell'attributo background non deve essere riscritto. Il tag html:rewrite genererà il nuovo codice HTML
background="/formulaire3/images/standard.jpg"
balise
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
traduction HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
explication
Il tag html:form consente di generare il tag HTML form. Presenta diversi attributi:
action
azione Struts a cui deve essere inviato il modulo - deve corrispondere a una delle azioni definite in struts-config.xml
name
facoltativo - nome del bean ActionForm o derivato in cui dovranno essere inseriti o letti i valori del modulo inviato. In assenza di questo attributo, viene utilizzato il modulo associato all’azione definita dall’attributo action. Questa informazione si trova nel file di configurazione (attributo name dell’azione).
type
facoltativo - classe Java da istanziare per il modulo. In assenza di questo attributo, viene utilizzata la classe associata all’azione definita dall’attributo action. Questa informazione si trova nel file di configurazione (attributo type dell’azione).
Si nota che, per impostazione predefinita, il codice HTML generato utilizza il metodo POST. Nello stesso codice HTML, il codice URL dell’azione è stato riscritto in modo da essere preceduto dal nome dell’applicazione e seguito dal suffisso .do.
balise
<html:radio name="dynaFormulaire" property="opt" value="sì">Sì</html:radio>
traduction HTML
<input type="radio" name="opt" value="oui">
explication
Il tag html:radio serve a generare il tag HTML <input type="radio" ...>. Accetta diversi attributi:
name
facoltativo - nome del bean ActionForm o derivato in cui dovrà essere inserito o letto il valore del campo. In assenza di questo attributo, viene utilizzato il modulo associato al tag <html:form>.
property
nome del campo del bean del modulo associato al pulsante di opzione in lettura e scrittura.
value
facoltativo - valore da assegnare al campo HTML
Il testo tra il tag di apertura e quello di chiusura è il testo che verrà visualizzato accanto al pulsante di opzione.
balise
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
traduction HTML
<input type="checkbox" name="chk1" value="on">
explication
Il tag html:checkbox serve a generare il tag HTML <input type="checkbox" ...>. Accetta diversi attributi:
name
facoltativo - nome del bean ActionForm o derivato in cui dovrà essere inserito o letto il valore del campo. In assenza di questo attributo, viene utilizzato il modulo associato al tag <html:form>.
property
nome del campo del bean del modulo associato alla casella di controllo in lettura e scrittura.
value
facoltativo - valore da assegnare al campo HTML
Il testo tra il tag di inizio e quello di fine è il testo che verrà visualizzato accanto alla casella di controllo.
balise
<html:text name="dynaFormulaire" property="champSaisie" />
traduction HTML
<input type="text" name="champSaisie" value="">
explication
Il tag html:text serve a generare il tag HTML <input type="text" ...>. Accetta diversi attributi:
name
facoltativo - nome del bean ActionForm o derivato in cui dovrà essere inserito o letto il valore del campo. In assenza di questo attributo, viene utilizzato il modulo associato al tag <html:form>.
property
nome del campo del bean del modulo associato al campo di immissione in lettura e scrittura.
value
facoltativo - valore da inserire nel campo HTML
balise
<html:password name="dynaFormulaire" property="mdp" />
traduction HTML
<input type="password" name="mdp" value="">
explication
Il tag html:password serve a generare il tag HTML <input type="password" ...>. Accetta diversi attributi:
balise
<html:textarea name="dynaFormulaire" property="boiteSaisie" />
traduction HTML
<textarea name="boiteSaisie"></textarea>
explication
Il tag html:textarea serve a generare il tag HTML <textarea>...</textarea>. Accetta diversi attributi:
name
facoltativo - nome del bean ActionForm o derivato in cui dovrà essere inserito o letto il valore del campo. In assenza di questo attributo, viene utilizzato il modulo associato al tag <html:form>.
property
nome del campo del bean del modulo associato al campo password in lettura e scrittura.
value
facoltativo - valore da assegnare al campo HTML
balise
<html:select name="dynaFormulaire" property="combo">....</html:select>
traduction HTML
<select name="combo">...</select>
explication
Il tag html:select serve a generare il tag HTML <select>...</select>. Accetta diversi attributi:
name
facoltativo - nome del bean ActionForm o derivato in cui dovrà essere inserito o letto il valore del campo. In assenza di questo attributo, viene utilizzato il modulo associato al tag <html:form>.
property
nome del campo del bean del modulo associato al campo di immissione in lettura e scrittura.
value
facoltativo - valore da assegnare al campo HTML. Verrà selezionata l'opzione del menu a tendina con questo valore.
balise
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="valeursCombo"/>
</html:select>
traduction HTML
<option value="combo1">combo1</option>
<option value="combo2">combo2</option>

explication
Il tag HTML:options serve a generare i tag HTML <option>...</option> all'interno di un tag HTML <select>. Esistono diversi modi per specificare come individuare i valori di riempimento del menu a tendina. In questo caso, abbiamo utilizzato gli attributi name e property:
name
facoltativo - nome del bean ActionForm o derivato in cui dovrà essere inserito o letto il valore del campo. In assenza di questo attributo, viene utilizzato il modulo associato al tag <html:form>.
property
nome del campo del bean del modulo che contiene i valori del select. Deve trattarsi di un array di stringhe.

Gli altri due elenchi vengono generati in modo analogo al precedente:

          <html:select name="dynaFormulaire" property="listeSimple" size="3">
            <html:options name="dynaFormulaire" property="valeursListeSimple"/>            
        </html:select>

Nell’esempio sopra riportato, si specifica un attributo size diverso da 1 per ottenere un elenco anziché un menu a tendina.

<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
        <html:options name="dynaFormulaire" property="valeursListeMultiple"/>                
    </html:select>

Qui sopra si specifica l'attributo multiple="true" per ottenere un elenco a selezione multipla.

balise
<html:hidden name="dynaFormulaire" property="secret"/>
traduction HTML
<input type="hidden" name="secret" value="xxx">
explication
Il tag html:hidden serve a generare il tag HTML <input type="hidden" ...>.
name
facoltativo - nome del bean ActionForm o derivato in cui dovrà essere inserito o letto il valore del campo. In assenza di questo attributo, viene utilizzato il modulo associato al tag <html:form>.
property
nome del campo del bean del modulo associato al campo nascosto. Il valore "xxx" assegnato al campo segreto HTML deriva dalla definizione del modulo nel file di configurazione. In esso è stato definito un valore iniziale "xxx" per il campo segreto.

Per comprendere appieno il collegamento tra la vista formulaire.jsp e il bean dynaFormulaire che la rappresenta in memoria, occorre ricordare che il bean dynaFormulaire viene utilizzato sia in lettura che in scrittura:

La richiesta viene effettuata quando l’utente fa clic sul pulsante [Envoyer] del modulo. Il browser “invia” quindi il modulo HTML all’azione /confirmation. Abbiamo già spiegato cosa succede in quel momento e, in particolare, che i campi di dynaFormulaire riceveranno i valori dei campi con lo stesso nome presenti nel modulo HTML.

Cosa succede quando il controller richiede la visualizzazione della vista formulaire.jsp in risposta a una richiesta? Esaminiamo nuovamente i tag uno per uno:

balise
<body background="<html:rewrite page="/images/standard.jpg"/>">
fonction
genera il codice HTML
<body background="/formulaire2/images/standard.jpg">
balise
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
</html:form>
fonction
genera il codice HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
balise
<html:radio name="dynaFormulaire" property="opt" value="sì">Sì</html:radio>
<html:radio name="dynaFormulaire" property="opt" value="no">No</html:radio>
fonction
Se il campo opt di dynaFormulaire è "sì", genera il codice HTML
<input type="radio" name="opt" value="oui" checked="checked">Oui
<input type="radio" name="opt" value="non">Non
balise
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk3">3</html:checkbox>
fonction
Se i campi chk1 e chk3 di dynaFormulaire hanno valore "on" e il campo chk2 ha valore "off", genera il codice HTML
<input type="checkbox" name="chk1" value="on" checked="checked">1
<input type="checkbox" name="chk2" value="on">2
<input type="checkbox" name="chk3" value="on" checked="checked">3                                                
balise
<html:text name="dynaFormulaire" property="champSaisie" />
fonction
se il campo champSaisie ha il valore "questo è un test", genera il codice HTML
<input type="text" name="champSaisie" value="ceci est un essai">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
se il campo mdp è pari a "azerty", genera il codice HTML
<input type="password" name="mdp" value="azerty">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
se il campo mdp è pari a "azerty", genera il codice HTML
<input type="password" name="mdp" value="azerty">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
se il campo mdp è pari a "azerty", genera il codice HTML
<input type="password" name="mdp" value="azerty">
balise
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="valeursCombo"/>
</html:select>
fonction
se il campo combo ha il valore "combo2", genera il codice HTML
<select name="combo">
    <option value="combo0">combo0</option>
    <option value="combo1">combo1</option>
    <option value="combo2" selected="selected">combo2</option>
    <option value="combo3">combo3</option>
    <option value="combo4">combo4</option>
</select>
balise
<html:select name="dynaFormulaire" property="listeSimple" size="3">
<html:options name="dynaFormulaire" property="valeursListeSimple"/>
</html:select>
fonction
se il campo listeSimple ha il valore "simple1", genera il codice HTML
<select name="listeSimple" size="3">
    <option value="simple0">simple0</option>
    <option value="simple1" selected="selected">simple1</option>
    <option value="simple2">simple2</option>
...
</select>
balise
<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
<html:options name="dynaFormulaire" property="valeursListeMultiple"/>
</html:select>
fonction
se il campo listeMultiple è l'array {"multiple0","multiple2"}, genera il codice HTML
<select name="listeMultiple" multiple="multiple" size="5">
    <option value="multiple0" selected="selected">multiple0</option>
    <option value="multiple1">multiple1</option>
    <option value="multiple2" selected="selected">multiple2</option>
    <option value="multiple3">multiple3</option>
...
</select>
balise
<html:hidden name="dynaFormulaire" property="secret"/>
fonction
se il campo segreto ha il valore "xxx", genera il codice HTML
<input type="hidden" name="secret" value="xxx">
balise
<html:submit>Invia</html:submit>
fonction
genera il codice HTML
<input type="submit" value="Envoyer">

L'ultima cosa da spiegare è il codice JavaScript incluso nella pagina JSP e collegato ai due pulsanti [Effacer] che deselezionano gli elementi selezionati negli elenchi listeSimple e listeMultiple:

<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>                                
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>

Il tag

<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">

genera il seguente codice HTML:

<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">

Per comprendere il codice JavaScript associato ai pulsanti [Effacer], ricordiamo come vengono identificati i diversi elementi di un documento web all’interno di un codice JavaScript che utilizza tale documento:

Dato
Significato
document
indica l’intero documento web
document.forms
indica l'insieme dei moduli definiti nel documento
document.forms[i]
indica il modulo n. i del documento
document.forms["nomFormulaire"]
indica il modulo <form> con l'attributo name pari a "nomFormulaire"
document.nomFormulaire
indica il modulo <form> con l'attributo name pari a "nomFormulaire"
document.[formulaire].elements
indica la raccolta degli elementi che compongono il modulo indicato dall'espressione [formulaire]. Questa raccolta comprende tutti i tag <input>, <textarea>, <select> del modulo indicato.
document.[formulaire].elements[i]
indica l'elemento n. i di [formulaire]
document.[formulaire].elements["nomComposant"]
indica l'elemento di [formulaire] con l'attributo "name" pari a nomComposant
document.[formulaire]. nomComposant
indica l'elemento di [formulaire] con l'attributo name pari a nomComposant
document.[formulaire].[composant].value
indica il valore del componente [composant] del modulo [formulaire] quando il codice HTML di quest’ultimo può avere un attributo value (<input>, <textarea>)
document.[formulaire].[select].selectedIndex
indica l'indice dell'opzione selezionata in un elenco. Si utilizza sia in lettura che in scrittura. Impostando questa proprietà su -1 si deseleziona tutti gli elementi dell'elenco.
document.[formulaire].[select].options
indica l'array delle opzioni associate a un tag <select>
document.[formulaire].[select].options[i]
indica l'opzione n. i del tag <select> specificato
document.[formulaire].[select].options[i].selected
valore booleano che indica se l'opzione n. i del tag [select] indicato è selezionata (true) o meno. Può essere utilizzato sia in lettura che in scrittura

Torniamo al codice JavaScript dei due pulsanti:

<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>                                
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>

All'evento clic sul pulsante, viene eseguito il codice associato all'attributo "onclick". In questo caso si tratta di codice in linea. Il più delle volte si scrive onclick="funzione(...)", dove funzione è una funzione definita all'interno di un tag <script language="javascript">...</script>. Cosa fa il codice sopra riportato? Commentiamo il codice del primo pulsante:

this
indica il documento web in cui si trova il pulsante
this.form
indica il modulo in cui si trova il pulsante
this.form.listeSimple
indica il componente listeSimple del modulo
this.form.listeSimple.selectedIndex
indica l'indice dell'opzione selezionata in listeSimple. Impostando questa proprietà su -1, tutte le opzioni vengono deselezionate.

6.4.2. La vista confirmation.jsp

Ricordiamo che questa vista viene visualizzata al termine dell’azione /conferma, c.a.d, dopo che il modulo contenuto nella vista formulaire.jsp è stato inviato dal client web. Il suo unico scopo è quello di visualizzare i valori inseriti dall’utente. Il suo codice è il seguente:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
    <head>
      <title>Confirmation</title>
  </head>
  <body background="<html:rewrite page="/images/standard.jpg"/>">
      <h3>Confirmation des valeurs saisies</h3>
    <hr/>
    <table border="1">
        <tr>
        <td>Bouton radio</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="opt"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk1</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk1"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk2</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk2"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk3</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk3"/></td>
      </tr>

        <tr>
        <td>Champ de saisie</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="champSaisie"/></td>
      </tr>
        <tr>
        <td>Mot de passe</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="mdp"/></td>
      </tr>

        <tr>
        <td>Boîte de saisie</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="boiteSaisie"/></td>
      </tr>

        <tr>
        <td>combo</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="combo"/></td>
      </tr>
        <tr>
        <td>liste simple</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="listeSimple"/></td>
      </tr>
            <logic:iterate id="choix" indexId="index" name="dynaFormulaire" property="listeMultiple">
          <tr>
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
        </tr>
            </logic:iterate>
    </table>
        <br>
    <html:link page="/affiche.do">
            Retour au formulaire
        </html:link>    
  </body>
</html>

Introduciamo qui due nuove librerie di tag: struts-bean e struts-logic. La libreria struts-bean consente di accedere agli oggetti presenti nella richiesta, nella sessione o nel contesto dell'applicazione. La libreria struts-logic consente di inserire la logica di esecuzione tramite tag. Queste due librerie non sono affatto indispensabili. Come abbiamo visto, una pagina JSP può:

  • recuperare oggetti dalla richiesta (request.getAttribute(...)), dalla sessione (session.getAttribute(...)) o dal contesto dell’applicazione
  • includere parti dinamiche nel codice HTML tramite variabili <%= variabile %>
  • contenere codice Java <% codice Java %>

L’inclusione di codice Java nelle pagine JSP crea difficoltà a tutti coloro che desiderano una separazione rigorosa tra logica applicativa (codice Java) e presentazione (uso dei tag). Per questo motivo sono state create delle librerie di tag appositamente per loro.

Procederemo come per la vista formulaire.jsp e spiegheremo ciascuno dei tag presenti nel codice di confirmation.jsp, qualora non fossero già stati incontrati nella vista formulaire.jsp. Innanzitutto, notiamo che la pagina inizia dichiarando le tre librerie di tag che utilizzerà:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

Ricordiamo inoltre che queste tre librerie devono essere dichiarate nel file web.xml dell’applicazione. Commentiamo ora i tag del documento formulaire.jsp:

balise
<bean:write name="dynaFormulaire" scope="session" property="opt"/>
fonction
scrive un valore nel flusso HTML corrente. Il tag bean:write ammette i seguenti attributi:
name: nome dell'oggetto da utilizzare
scope: ambito (request, session, context) in cui cercare tale oggetto
property: campo dell'oggetto indicato da name di cui si deve scrivere la proprietà. Questo campo può essere un oggetto di qualsiasi tipo. Verrà utilizzato il metodo toString dell'oggetto.
In questo caso, viene scritto il valore del campo opt di dynaFormulaire. Si otterrà “sì” se l’utente ha selezionato il pulsante di opzione con l’attributo value=”sì”, oppure “no” se ha selezionato il pulsante di opzione con l’attributo value=”no”
balise
<bean:write name="dynaFormulaire" scope="session" property="chk1"/>
fonction
scrive il valore del campo chk1 di dynaFormulaire. Si otterrà "on" se l'utente ha selezionato la casella, oppure "off" in caso contrario. Lo stesso vale per chk2 e chk3.
balise
<bean:write name="dynaFormulaire" scope="session" property="champSaisie"/>
fonction
scrive il valore del campo champSaisie da dynaFormulaire, ovvero il testo digitato dall’utente in quel campo. Lo stesso vale per mdp, boiteSaisie.
balise
<bean:write name="dynaFormulaire" scope="session" property="combo"/>
fonction
scrive il valore del campo a discesa di dynaFormulaire. Si otterrà l’attributo value dell’elemento <option> selezionato dall’utente.
balise
<bean:write name="dynaFormulaire" scope="session" property="listeSimple"/>
fonction
scrive il valore del campo listeSimple da dynaFormulaire. Si otterrà l'attributo value dell'elemento <option> selezionato dall'utente, se ne è stato selezionato uno. In caso contrario, si otterrà la stringa vuota.
balise
            <logic:iterate id="choix" indexId="index" name="dynaFormulaire" property="listeMultiple">
          <tr>
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
        </tr>
            </logic:iterate>
fonction
Qui introduciamo dei tag logici. Abbiamo a che fare con un elenco a scelta multipla. Il valore del campo listeMultiple dell'oggetto dynaFormulaire è un array di String. In Java, scriveremmo un ciclo. Il tag logic:iterate ci permette di eseguire lo stesso ciclo senza scrivere codice Java. Nel nostro esempio, il tag logic:iterate presenta i seguenti attributi:
name="dynaFormulaire": nome dell’oggetto da utilizzare
property="listeMultiple": nome della proprietà che, nell’oggetto indicato da name, contiene la collezione che verrà iterata nel ciclo. In questo caso, tale collezione è l’array dei valori selezionati in listeMultiple. Questo array può essere vuoto.
id="choix": identificatore che indica l'elemento corrente dell'array ad ogni iterazione del ciclo. Durante la prima iterazione, «choix» rappresenterà listeMultiple[0], durante la seconda listeMultiple[1] e così via.
indexID="index": identificatore che indica l'indice dell'elemento corrente dell'array ad ogni iterazione del ciclo. Nella prima iterazione, index avrà il valore 0, nella seconda il valore 1 e così via.
Il codice HTML contenuto tra i tag <logic:iterate ...> e </logic:iterate> viene ripetuto per ogni elemento della collezione indicata dalla coppia (name,property). La parte dinamica di questo codice è la seguente:
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
Da quanto detto in precedenza, all’iterazione n. i (i>=0), il codice HTML generato è equivalente al seguente codice:
          <td>liste multiple[<%=i%>]</td>
          <td><%=listeMultiple[i]%></td>
balise
    <html:link page="/affiche.do">
            Retour au formulaire
        </html:link>    
fonction
genera un link relativo al contesto dell'applicazione, il che evita di doverlo conoscere. Il codice HTML generato da questo tag è il seguente:
<a href="/formulaire2/affiche.do">Retour au formulaire</a>

6.5. Le classi Java

Il file di configurazione struts-config.xml fa riferimento a due classi Java:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >

La classe DynaFormulaire è la classe che conterrà i valori della vista n. 1 formulaire.jsp. La classe InitFormulaireAction è la classe che elaborerà i valori del modulo inviato tramite il pulsante [Envoyer] di formulaire.jsp.

6.5.1. La classe DynaFormulaire

Per contenere i valori di un modulo, è sufficiente un oggetto di tipo DynaActionForm, a meno che non sia necessario ridefinire uno dei metodi reset o validate di questa classe. In questo caso, il metodo validate non deve essere ridefinito poiché non viene eseguita alcuna convalida dei dati. Il metodo reset, invece, deve essere ridefinito. Infatti, i campi dell’oggetto DynaFormulaire riceveranno i propri valori dal modulo inviato dal client web. Tuttavia, alcuni campi potrebbero non ricevere alcun valore se non sono presenti nella richiesta. Ciò si verifica nei seguenti casi:

  • una casella di selezione che non è stata spuntata dall'utente
  • un elenco con più di una voce o nessuna opzione selezionata

Per i moduli che contengono questo tipo di componente, il metodo reset deve

  • assegnare il valore "off" al campo associato alla casella di controllo
  • assegnare la stringa vuota al campo associato a un elenco a selezione singola
  • assegnare un array di stringhe di lunghezza zero al campo associato a un elenco a selezione multipla

Pertanto, se questi campi non ricevono alcun valore dalla richiesta, mantengono il valore assegnato dal metodo reset, valore che corrisponde allo stato del componente nel modulo convalidato dall’utente (casella deselezionata, elenco senza alcun elemento selezionato).

Il codice della classe DynaFormulaire, classe derivata da DynaActionForm, è il seguente:

package istia.st.struts.formulaire;

import org.apache.struts.action.DynaActionForm;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;

public class DynaFormulaire extends DynaActionForm {
  public void reset(ActionMapping mapping, HttpServletRequest request){
    // reset delle caselle di controllo - valore off
    set("chk1","off");
    set("chk2","off");
    set("chk2","off");
    // reset di listeSimple - stringa vuota
    set("listeSimple","");
     // reset di listeMultiple - tabella vuota
    set("listeMultiple",new String[]{});
  }
}

6.5.2. La classe InitFormulaireAction

La classe InitFormulaireAction è, nel file struts-config.xml, associata all'azione /init:

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

L'azione /init viene utilizzata una sola volta durante la creazione iniziale dell'oggetto DynaFormulaire. Ha lo scopo di fornire contenuti ai tre elenchi del form a discesa, listeSimple, listeMultiple. Tale contenuto viene fornito sotto forma di tre array, proprietà dell’oggetto dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
...
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                                          
        </form-bean>            

Una volta che le tabelle valeursCombo, valeursListeSimple, valeursListeMultiple saranno state inizializzate da InitFormulaireAction, non sarà più necessario inizializzarle nuovamente. Infatti, l’oggetto dynaFormulaire viene inserito nella sessione e mantiene quindi il proprio valore nel corso dei cicli richiesta-risposta. Per questo motivo l’azione /init viene eseguita una sola volta. Il codice di InitFormulaireAction è il seguente:

package istia.st.struts.formulaire;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;

public class InitFormulaireAction
  extends Action {
  public ActionForward execute(ActionMapping mapping, ActionForm form,
       HttpServletRequest request, HttpServletResponse response) throws IOException,    ServletException {

     // prepara il modulo da visualizzare

     // si inseriscono le informazioni necessarie nel bean del modulo
    DynaFormulaire formulaire = (DynaFormulaire) form;
    formulaire.set("valeursCombo", getValeurs(5, "combo"));
    formulaire.set("valeursListeSimple", getValeurs(7, "simple"));
    formulaire.set("valeursListeMultiple", getValeurs(10, "multiple"));
     // si restituisce il controllo
    return mapping.findForward("afficherFormulaire");
  } //esegue

   // elenco dei valori del menu a tendina
  private String[] getValeurs(int taille, String label) {
    String[] valeurs = new String[taille];
    for (int i = 0; i < taille; i++) {
      valeurs[i] = label + i;
    }
    return valeurs;
  }
}
  • La classe deriva dalla classe Action. È obbligatorio.
  • Il controller Struts utilizza un oggetto Action tramite il suo metodo execute. È quindi questo metodo che deve essere ridefinito. Questo metodo riceve i seguenti parametri:
    • ActionMapping mapping: un oggetto che rappresenta la configurazione dell'applicazione in struts-config.xml
    • ActionForm form: il modulo associato all’azione, se ne è stato definito uno nella configurazione dell’azione (attributo name dell’azione).
    • HttpServletRequest request: la richiesta del client
    • HttpServletResponse: la risposta al client
  • la classe InitFormulaireAction deve inizializzare il modulo dynaFormulaire. Quest'ultimo viene passato al metodo execute sotto forma del parametro ActionForm form. Ricordiamo che dynaFormulaire è di tipo DynaFormulaire, classe derivata dalla classe DynaActionForm, a sua volta derivata dalla classe ActionForm.
  • Nel metodo `execute`, vengono assegnati dei valori ai tre campi valeursCombo, valeursListeSimple e valeursListeMultiple tramite il metodo `set` della classe DynaActionForm. Questi valori sono array arbitrari per motivi di semplicità. Si noti che il metodo set assegna un valore a un campo esistente. Non può essere utilizzato per creare nuovi campi. Per questo motivo, è necessario definire i tre campi valeursCombo, valeursListeSimple, valeursListeMultiple nella definizione dell'oggetto dynaFormulaire in struts-config.xml.
  • Il metodo `execute` termina restituendo al controller la chiave della vista da visualizzare come risposta al client. In questo caso, si tratta della chiave afficherFormulaire che, nel file struts-config.xml, è stata associata alla vista /vues/formulaire.jsp.

6.6. Distribuzione

La struttura dell'applicazione è la seguente:

  

Image

Image

Ricordiamo che il file ApplicationResources.properties sopra riportato è necessario per la libreria di tag struts-bean. È noto che questo file contiene i messaggi dell'applicazione. Questi sono accessibili alla libreria struts-bean. In questo caso, la nostra applicazione non definisce alcun messaggio. Pertanto, il file ApplicationResources.properties esiste ma è vuoto.

6.7. Conclusione

In questa lezione abbiamo illustrato in dettaglio come gestire i diversi componenti di un modulo HTML. Ora possiamo utilizzare moduli complessi nelle nostre applicazioni Struts.