Skip to content

6. Moduli HTML

Finora abbiamo utilizzato un unico modulo contenente solo due campi di immissione. Qui proponiamo di creare ed elaborare un modulo utilizzando componenti grafici standard (pulsanti di opzione, caselle di controllo, campi di immissione, caselle combinate, elenchi).

6.1. Le viste dell'applicazione

L'applicazione avrà solo due viste. La prima visualizza un modulo vuoto:

VISTA 1 - modulo

Image

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

Image

Il pulsante [Invia] conferma i 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 [Torna al modulo] ci permette di tornare al modulo così come lo abbiamo compilato. Verremo quindi riportati alla prima vista.

6.2. L'architettura dell'applicazione

  • Il modulo (vista 1) sarà rappresentato da un oggetto Struts dinamico denominato dynaFormulaire, una sottoclasse di DynaActionForm. Verrà visualizzato dalla vista form.jsp.
  • L'azione Struts InitFormulaireAction sarà responsabile del recupero dei dati necessari per visualizzare il modulo
  • Il modulo compilato verrà elaborato da una ForwardAction, che si limiterà a reindirizzare la richiesta alla seconda vista, confirmation.jsp. Questa vista sarà responsabile della visualizzazione dei valori del modulo.

6.3. Configurazione dell'applicazione

6.3.1. Il file server.xml

Il contesto dell'applicazione sarà denominato /formulaire2. Aggiungeremo quindi la seguente riga al file server.xml di Tomcat:

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

Una volta fatto ciò, potrebbe essere necessario riavviare 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 che abbiamo già visto, stiamo apportando alcune modifiche:

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

6.3.3. Il file struts-config.xml

Il file struts-config.xml sarà 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>

Contiene 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-resources>

6.3.4. Gli oggetti modulo (bean) dell'applicazione

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

  • per contenere i dati necessari alla visualizzazione della vista n. 1
  • recuperare i valori dal modulo nella vista n. 1 quando l'utente lo invia
  • per contenere i dati necessari per visualizzare la vista n. 2

La struttura del bean dynaFormulaire è strettamente legata al modulo nella vista n. 1. Esaminiamola:

N.
Tipo HTML
Ruolo
1
<input name="opt" type="radio" value="yes">
<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
(non è lo stesso nome)
3
<input type="text" name="inputField">
un campo di testo
4
<input type="password" name="password">
un campo password
5
<textarea name="inputBox">...</textarea>
un campo di immissione multilinea
6
<select name="combo" size="1">..</select>
un menu a tendina
7
<select name="simpleList" 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='clearList("singleList")'>
pulsante per deselezionare
gli elementi selezionati in simpleList (7)
10
<input type="button" value="Cancella"
onclick='clearList("multipleList")'>
pulsante per deselezionare
gli elementi selezionati in multipleList (8)
11
<input type="submit" value="Invia">
pulsante di invio del modulo
12
<input type="hidden" name="secret" value="...">
un campo nascosto

Consideriamo diversi casi:

  1. L'oggetto dynaFormulaire viene utilizzato per contenere i valori del modulo HTML sopra riportato, che verranno inviati tramite il pulsante [Invia]. Deve quindi avere gli stessi campi del modulo HTML. Il tipo di campo è determinato dalla seguente regola:
  • se il campo HTML fornisce un solo valore, il campo dynaFormulaire sarà di tipo java.lang.String
  • se il campo HTML fornisce più valori, il campo 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 definizione iniziale 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>            

In che modo dynaFormulaire verrà popolato con i valori del modulo HTML inviati dal client web?

opt
Il campo opt riceverà il valore "yes" se è stato selezionato il campo HTML <input type="radio" name="opt" value="yes">, e il valore "no" se è stato selezionato il campo <input type="radio" name="opt" value="no">.
chk1
Il campo chk1 riceverà il valore "on" se è stato selezionato il campo HTML <input name="chk1" type="radio" value="1">; in caso contrario, non riceverà nulla. In quest'ultimo caso, il campo chk1 manterrà il suo valore precedente.
chk2
stesso
chk3
uguale
campo di immissione
Il campo `champSaisie` riceverà il testo inserito dall'utente nel campo HTML `<input type="text" name="champSaisie">`. Questo testo può essere una stringa vuota.
password
Il campo mdp riceverà il testo inserito dall'utente nel campo HTML <input type="password" name="mdp">. Questo testo può essere una stringa vuota.
textarea
Il campo inputBox riceverà il testo inserito dall'utente nel campo HTML <textarea name="inputBox">...</textarea>. Questo testo forma una singola stringa, costituita dalle righe digitate dall'utente separate l'una dall'altra dalla sequenza di caratteri "\r\n". Il testo risultante può essere, facoltativamente, una stringa vuota.
combo
Il campo combo riceverà l'opzione selezionata dall'utente nel campo HTML <select name="combo" size="1">..</select>. L'opzione selezionata è quella che appare nella casella combinata. Se l'opzione HTML selezionata è del tipo <option value="XX">YY</option>, il campo combo riceverà il valore "XX". Se l'opzione HTML selezionata è del tipo <option>YY</option>, il campo combo riceverà il valore "YY".
simpleList
Il campo simpleList riceverà l'opzione selezionata dall'utente nel campo HTML <select name="simpleList" size="..">..</select> se presente. Se non ce n'è nessuna, il campo simpleList non riceverà alcun valore e manterrà il suo valore precedente. Il valore effettivamente assegnato al campo simpleList segue le regole specificate per la casella combinata.
listeMultiple
Il campo listeMultiple di tipo String[] riceverà le opzioni selezionate dall'utente nel campo HTML <select name="listeMultiple" size=".." multiple>..</select>, se presenti. In assenza di opzioni, l'array listeMultiple non riceverà alcun valore e il suo contenuto rimarrà invariato. I valori effettivamente assegnati all'array listeMultiple seguono le regole specificate per la casella combinata.
secret
Il campo secret riceverà il valore XX dal campo HTML <input type="hidden" name="secret" value="XX">. Questo testo può essere facoltativamente 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
deve avere il valore "yes" o "no" in modo che 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
uguale
campo di immissione
il valore del campo verrà visualizzato nel campo di immissione fieldInput
password
il valore del campo verrà visualizzato nel campo di immissione mdp
casella di immissione
il valore del campo verrà visualizzato nella casella di immissione inputBox
combo
Il valore di questo campo indica quale voce della casella combinata deve essere selezionata quando viene visualizzato il modulo
simpleList
same
multipleList
I valori nell'array multipleList indicano quali elementi dell'elenco multiplo devono essere selezionati quando viene visualizzato il modulo
segreto
Il valore del campo verrà assegnato all'attributo value del campo HTML secret.

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 multipleList

Esistono diversi modi per fornire queste informazioni alla vista. Ad esempio, funzionerebbero gli array inseriti nella richiesta passata alla vista. In questo caso, inseriamo questi array 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. Questo oggetto avrà il compito di creare i tre array necessari per visualizzare i tre elenchi e di inserirli nel bean dynaFormulaire. Il file di configurazione imposta l'ambito di questo bean su session. Di conseguenza, il controller Struts inserirà questo bean nella sessione. Non sarà quindi necessario rigenerarlo tra i cicli richiesta-risposta. Di conseguenza, l'azione /init verrà chiamata una sola volta.

  1. L'oggetto dynaFormulaire viene utilizzato anche per popolare la vista n. 2. Questa vista si limita a visualizzare i valori.

6.3.5. Azioni dell'applicazione

Le azioni sono gestite da oggetti di tipo Action o tipi derivati. La configurazione delle azioni viene effettuata 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, rivediamo come funziona la coppia azione-modulo all'interno di un tag <action>:

  • Un'azione inizia con una richiesta proveniente da un client web e termina con l'invio di una pagina di risposta. Questo è il ciclo client-server di richiesta-risposta web. La richiesta viene ricevuta dal controller Struts di tipo ActionServlet o da una classe derivata. Questo controller invia anche la risposta.
  • Il bean del modulo di tipo ActionForm o una classe derivata viene creato se non esiste già. Il controller verifica se riesce a trovare un oggetto denominato name nell'ambito specificato da scope. In caso affermativo, lo utilizza. In caso contrario, lo crea e lo inserisce nell'ambito specificato da scope, associato all'attributo specificato da name.

Nell'esempio dell'azione /init, ad esempio, il controller chiamerà request.getSession().getAttribute("dynaFormulaire") per determinare se dynaFormulaire è già stato creato o meno. In caso contrario, lo creerà e lo aggiungerà alla sessione utilizzando un'istruzione come request.getSession().setAttribute("dynaFormulaire", new DynaFormulaire(...)).

  • Il controller cercherà anche un oggetto Action del tipo specificato dall'attributo type. Se non ne trova uno, lo crea; altrimenti, lo utilizza.
  • Verrà chiamato il metodo reset del bean del modulo. Questo bean, tranne che durante la sua creazione iniziale, viene riutilizzato. Contiene quindi dati che potresti voler "ripulire". Ciò viene fatto nel metodo reset del bean ActionForm o di una classe derivata.
  • Se l'azione è la destinazione di un modulo inviato, i valori del modulo presenti nella richiesta del client vengono copiati nei campi con lo stesso nome nel 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. Questo metodo deve quindi convalidare i dati nel bean. Questa convalida avviene in genere solo quando il modulo ha appena ricevuto nuovi dati tramite un modulo inviato e si desidera verificare la validità di tali dati. Questo metodo restituisce un elenco di errori al controller in un oggetto ActionErrors.
  • Se l'oggetto ActionErrors non è vuoto, il controller visualizza la vista specificata dall'attributo input dell'azione.
  • Se la convalida dei dati non è richiesta o se ha avuto esito positivo, il controller chiama il metodo `execute` dell'oggetto `Action` (o di una classe derivata) associato all'azione corrente. È all'interno di questo metodo che viene elaborata la richiesta del client web. Il metodo `execute` restituisce un oggetto `ActionForward` indicizzato da chiavi stringa. Queste chiavi sono quelle dichiarate dai tag `forward` dell'azione configurata. Nel nostro esempio, l'azione `/init` ha un unico tag `forward`. Esso associa la chiave "displayForm" alla vista `form.jsp`.
  • Il controller visualizza la vista associata alla 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 si verifica normalmente una volta durante il primo ciclo richiesta-risposta quando l'utente richiede l'URL http://localhost:8080/formulaire2/init.do
  • L'oggetto dynaForm viene creato o riciclato. Viene recuperato (riciclaggio) o inserito (creazione) nella sessione come specificato dall'attributo scope.
  • Viene chiamato il suo metodo reset. Cosa dovrebbe fare? Normalmente, i campi dell'oggetto ActionForm vengono reimpostati ai valori predefiniti. Tuttavia, in questo caso, non lo faremo, perché l'oggetto dynaFormulaire viene inserito nella sessione (scope="session"). I campi di dynaFormulaire devono quindi mantenere i loro valori. Quali sono questi valori durante la creazione iniziale dell'oggetto dynaFormulaire? Ci sono 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 questo 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 avranno la stringa vuota e gli altri oggetti avranno il valore null.

Diamo un'occhiata alla 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 dynaFormulaire dopo la creazione saranno i seguenti:

Campo
Valore iniziale
opt
"no"
chk1, chk2, chk3
stringa vuota
campo di immissione
stringa vuota
mdp
stringa vuota
casella di immissione
stringa vuota
elenco a discesa
stringa vuota
elenco semplice
stringa vuota
elenco multiplo
array di stringhe vuote
segreto
"xxx"
comboValues, singleList, multipleList
array di stringhe vuote
  • Si potrebbe immaginare che il metodo reset di dynaFormulaire assegni valori ai tre array che popolano le tre liste nella vista formulaire.jsp. Ciò sarebbe possibile in questo caso poiché i dati in questi tre array vengono generati in modo arbitrario. Tuttavia, lo scenario più comune è che questi dati provengano dal modello dell'applicazione, la M in MVC. Qui, per mantenere l'esempio semplice, adotteremo una via di mezzo, facendo generare questi valori dall'azione InitFormulaireAction, ovvero dalla C in MVC.
  • Non è necessario 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, ha il valore "false". Il metodo validate di dynaFormulaire non verrà chiamato.
  • L'oggetto InitFormulaireAction viene creato o riutilizzato se già esisteva, e viene chiamato il suo metodo execute. Questo metodo assegna valori arbitrari ai tre array di dynaFormulaire: valeursCombo, valeursListeSimple e valeursListeMultiple. Il metodo restituisce un ActionForward con la chiave "afficherFormulaire".
  • Il controller visualizza la vista /vues/formulaire.jsp, che è stata associata alla chiave "afficherFormulaire" tramite un tag forward dall'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 si verifica quando l'utente fa clic sul pulsante [Invia] nella vista n. 1. Il browser quindi "invia" il modulo compilato dall'utente al controller Struts.
  • L'oggetto dynaFormulaire viene recuperato dalla sessione
  • viene chiamato il suo metodo reset. Una volta chiamato, il controller Struts copierà i valori dei campi del modulo inviati dal client nei campi con lo stesso nome in dynaFormulaire. Esaminiamo l'elenco dei campi in dynaFormulaire e vediamo come funziona questa copia:
Campo
Codice HTML associato
Valore del campo
dopo la copia dei valori del modulo
opt
<input type="radio" name="opt" value="yes">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 di controllo chk1 è stata selezionata
- mantiene il valore precedente se la casella di controllo chk1 non è stata selezionata
chk2
<input type="checkbox" name="chk2" value="on">
- "on" se la casella di controllo chk2 è stata selezionata
- mantiene il valore precedente se la casella di controllo chk2 non è stata selezionata
chk3
<input type="checkbox" name="chk2" value="on">
- "on" se la casella di controllo chk3 è stata selezionata
- mantiene il valore precedente se la casella di controllo chk3 non è stata selezionata
campo di immissione
<input type="text" name="inputField" value="">
- valore inserito dall'utente in inputField
password
<input type="password" name="password" value="">
- valore inserito dall'utente nel campo password
casella di immissione
<textarea name="inputBox"></textarea>
- valore inserito dall'utente nella casella di testo
combo
<select name="combo">...</select>
- valore selezionato dall'utente nel menu a tendina
simpleList
<select name="simpleList" size="3">...</select>
- valore selezionato dall'utente in simpleList
multipleList
<select name="listeMultiple" multiple="multiple" size="5">
- array di stringhe contenente i valori selezionati dall'utente in multipleList
secret
<input type="hidden" name="secret" value="xxx">
- "xxx".

Si verifica un problema con i campi che non ricevono necessariamente un valore nella richiesta inviata dal browser. Ciò vale per le caselle di controllo da chk1 a chk3 e per i due elenchi listeSimple e listeMultiple. In questo caso, questi campi mantengono i valori precedenti, ovvero quelli acquisiti durante il ciclo di richiesta-risposta precedente.

Prendiamo ad esempio la casella di controllo chk1 e supponiamo che, nel ciclo di richiesta-risposta precedente, l'utente l'abbia selezionata. Il browser ha quindi inviato l'informazione chk1="on" nella stringa dei parametri della sua richiesta. Il costruttore ha quindi assegnato il valore "on" al campo chk1 di dynaFormulaire. Supponiamo ora che, nel ciclo corrente, l'utente non selezioni la casella di controllo 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 in dynaFormulaire manterrà il suo valore "on" e avrà quindi un valore che non riflette quello del modulo convalidato dall'utente. Useremo il metodo reset di dynaFormulaire per risolvere questo problema. In questo metodo, imposteremo i tre campi chk1, chk2 e chk3 su "off". Nel nostro esempio chk1, l'utente:

  • selezionerà la casella di controllo chk1. In questo caso, il browser invierà l'informazione chk1="on" e il campo chk1 in dynaFormulaire passerà a "on"
  • non seleziona la casella di controllo chk1. In questo caso, il browser non invia alcun valore per il campo chk1, che manterrà il suo valore precedente "off". In entrambi i casi, il valore memorizzato nel campo chk1 di dynaFormulaire è corretto.

Il problema è simile sia per l'elenco simpleList che per quello multiList. Se in questi elenchi non è stata selezionata alcuna opzione, essi non saranno presenti nei parametri della richiesta e manterranno quindi i loro valori precedenti. Nel metodo reset di dynaFormulaire, reimposteremo simpleList con una stringa vuota e multiList con un array di stringhe di lunghezza 0.

  • Una volta chiamato il metodo reset di dynaFormulaire, il controller ricopia le informazioni che gli sono state inviate nella richiesta del client nei campi di dynaFormulaire
  • Viene creato o riutilizzato 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 è completo.

Il /display

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • L'azione /display viene attivata cliccando sul link [Torna al modulo] nella vista n. 2.
  • In questo caso, non vi è alcun modulo associato all'azione. Si procede quindi direttamente all'esecuzione del metodo `execute` di un oggetto `ForwardAction`, che restituirà un oggetto `ActionForward` puntante alla vista `/vues/formulaire.jsp`.

6.3.6. Il file dei messaggi dell'applicazione

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

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

Il file ApplicationResources.properties si trova in 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 viene utilizzata dalla vista confirmation.jsp.

6.4. Il codice della vista

6.4.1. La vista formulaire.jsp

Ricordate che questa vista viene visualizzata in due casi:

  • quando viene chiamata l'azione /init durante il primo ciclo richiesta-risposta
  • quando viene chiamata l'azione /affiche durante i 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 i tag della libreria struts-html. Ricorda che per utilizzare una libreria di tag devi:

  • dichiararla nel file web.xml dell'applicazione utilizzando un tag <tag-lib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  • Inserisci il codice di questa libreria in una posizione qualsiasi all'interno dell'albero delle directory dell'applicazione, in questo caso WEB-INF/struts-html.tld
  • Dichiarare l'uso 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 tag che spiegheremo ora:

tag
<body background="<html:rewrite page="/images/standard.jpg"/>">
Traduzione HTML
<body background="/formulaire2/images/standard.jpg">
spiegazione
Il tag html:rewrite consente di omettere il nome dell'applicazione dagli URL. Ha un solo attributo:
pagina
URL da riscrivere
Quindi, nell'esempio sopra riportato, se si decide di chiamare l'applicazione "form3", non è necessario riscrivere il codice dell'attributo background. Il tag `html:rewrite` genererà il nuovo codice HTML
background="/formulaire3/images/standard.jpg"
tag
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
Traduzione HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
spiegazione
Il tag html:form genera il tag HTML form. Ha diversi attributi:
action
Azione Struts a cui il modulo deve essere inviato — deve corrispondere a una delle azioni definite in struts-config.xml
name
opzionale - nome del bean ActionForm o di una sua sottoclasse in cui devono essere inseriti o letti i valori del modulo inviato. Se questo attributo viene omesso, viene utilizzato il modulo associato all'azione definita dall'attributo action. Questa informazione si trova nel file di configurazione (l'attributo name dell'azione).
type
facoltativo - Classe Java da istanziare per il modulo. Se questo attributo viene omesso, viene utilizzata la classe associata all'azione definita dall'attributo action. Queste informazioni sono contenute nel file di configurazione (attributo type dell'azione).
Possiamo notare che, per impostazione predefinita, il codice HTML generato utilizza il metodo POST. Nello stesso codice HTML, l'URL dell'azione è stato riscritto in modo da essere preceduto dal nome dell'applicazione e seguito dal suffisso .do.
tag
<html:radio name="dynaFormulaire" property="opt" value="yes">Sì</html:radio>
Traduzione HTML
<input type="radio" name="opt" value="yes">
spiegazione
Il tag html:radio viene utilizzato per generare il tag HTML <input type="radio" ...>. Supporta vari attributi:
name
opzionale - nome del bean ActionForm o di un bean derivato in cui deve essere inserito o letto il valore del campo. Se questo attributo viene omesso, viene utilizzato il modulo associato al tag <html:form>.
property
Nome del campo nel bean del modulo associato al pulsante di opzione per la lettura e la scrittura.
valore
facoltativo - valore da assegnare al campo HTML
Il testo tra i tag di inizio e fine è il testo che verrà visualizzato accanto al pulsante di opzione.
tag
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
Traduzione HTML
<input type="checkbox" name="chk1" value="on">
spiegazione
Il tag html:checkbox viene utilizzato per generare il tag HTML <input type="checkbox" ...>. Supporta vari attributi:
name
opzionale - nome del bean ActionForm o di un bean derivato in cui deve essere inserito o letto il valore del campo. Se questo attributo viene omesso, viene utilizzato il modulo associato al tag <html:form>.
property
Nome del campo nel bean del modulo associato alla casella di controllo per la lettura e la scrittura.
valore
facoltativo - valore da assegnare al campo HTML
Il testo tra i tag di inizio e fine è il testo che verrà visualizzato accanto alla casella di controllo.
tag
<html:text name="dynaFormulaire" property="inputField" />
Traduzione HTML
<input type="text" name="inputField" value="">
spiegazione
Il tag html:text viene utilizzato per generare il tag HTML <input type="text" ...>. Supporta vari attributi:
name
facoltativo - nome del bean ActionForm o di un bean derivato in cui deve essere inserito o letto il valore del campo. Se questo attributo viene omesso, viene utilizzato il modulo associato al tag <html:form>.
proprietà
Nome del campo nel bean del modulo associato al campo di input in lettura-scrittura.
valore
facoltativo - valore da assegnare al campo HTML
tag
<html:password name="dynaFormulaire" property="mdp" />
Traduzione HTML
<input type="password" name="mdp" value="">
spiegazione
Il tag html:password viene utilizzato per generare il tag HTML <input type="password" ...>. Supporta vari attributi:
tag
<html:textarea name="dynaFormulaire" property="boiteSaisie" />
Traduzione HTML
<textarea name="boiteSaisie"></textarea>
spiegazione
Il tag HTML:textarea viene utilizzato per generare il tag HTML <textarea>...</textarea>. Supporta vari attributi:
name
opzionale - nome del bean ActionForm o di un bean derivato in cui il valore del campo deve essere inserito o letto. Se questo attributo viene omesso, viene utilizzato il modulo associato al tag <html:form>.
property
Nome del campo nel bean del modulo associato al campo password per la lettura e la scrittura.
valore
facoltativo - valore da assegnare al campo HTML
tag
<html:select name="dynaFormulaire" property="combo">....</html:select>
Traduzione HTML
<select name="combo">...</select>
spiegazione
Il tag HTML:select viene utilizzato per generare il tag HTML <select>...</select>. Supporta vari attributi:
name
opzionale - nome del bean ActionForm o del bean derivato in cui deve essere inserito o letto il valore del campo. Se questo attributo viene omesso, viene utilizzato il modulo associato al tag <html:form>.
property
Nome del campo nel bean del modulo associato al campo di input in lettura-scrittura.
valore
facoltativo - valore da assegnare al campo HTML. Verrà selezionata l'opzione della casella combinata con questo valore.
tag
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="comboValues"/>
</html:select>
Traduzione HTML
<option value="combo1">combo1</option>
<option value="combo2">combo2</option>

spiegazione
Il tag HTML:options viene utilizzato per generare i tag HTML <option>...</option> all'interno di un tag HTML <select>. Esistono vari modi per specificare come trovare i valori con cui popolare l'elemento select. In questo caso, abbiamo utilizzato gli attributi name e property:
name
opzionale - nome del bean ActionForm o del bean derivato in cui il valore del campo deve essere inserito o letto. Se questo attributo viene omesso, viene utilizzato il modulo associato al tag <html:form>.
property
Nome del campo nel bean del modulo che contiene i valori di selezione. Deve essere un array di stringhe.

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

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

Sopra, specifichiamo un attributo size diverso da 1 per creare un elenco anziché una casella combinata.

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

Sopra, specifichiamo l'attributo multiple="true" per creare un elenco con selezioni multiple.

tag
<html:hidden name="dynaFormulaire" property="secret"/>
Traduzione HTML
<input type="hidden" name="secret" value="xxx">
spiegazione
Il tag html:hidden viene utilizzato per generare il tag HTML <input type="hidden" ...>.
nome
opzionale - nome del bean ActionForm o del bean derivato in cui deve essere inserito o letto il valore del campo. Se questo attributo viene omesso, viene utilizzato il modulo associato al tag <html:form>.
proprietà
Nome del campo nel bean del modulo associato al campo nascosto. Il valore "xxx" assegnato al campo HTML segreto proviene dalla definizione del modulo nel file di configurazione. Lì è stato definito un valore iniziale di "xxx" per il campo segreto.

Per comprendere appieno la relazione tra la vista formulaire.jsp** e il bean dynaFormulaire che la rappresenta in memoria, è importante ricordare che il bean dynaFormulaire** viene utilizzato sia per la lettura che per la scrittura:

La richiesta avviene quando l'utente clicca sul pulsante [Invia] nel modulo. Il browser quindi "invia" il modulo HTML all'azione /confirmation. Abbiamo già spiegato cosa succede in seguito, e in particolare che i campi dynaFormulaire riceveranno i valori dei campi con lo stesso nome nel modulo HTML.

Cosa succede quando il controller richiede la visualizzazione della pagina formulaire.jsp in risposta a una richiesta? Diamo un'occhiata più da vicino ai tag uno per uno:

tag
<body background="<html:rewrite page="/images/standard.jpg"/>">
funzione
genera il codice HTML
<body background="/formulaire2/images/standard.jpg">
tag
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
</html:form>
funzione
genera il codice HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
tag
<html:radio name="dynaFormulaire" property="opt" value="yes">Sì</html:radio>
<html:radio name="dynaFormulaire" property="opt" value="no">No</html:radio>
funzione
Se il campo opt di dynaFormulaire è "yes", genera il codice HTML
<input type="radio" name="opt" value="yes" checked="checked"><input type="radio" name="opt" value="no">No
tag
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
<html:checkbox name="dynaForm" property="chk3">3</html:checkbox>
funzione
Se i campi chk1 e chk3 di dynaFormulaire sono "on" e il campo chk2 è "off", generare 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
tag
<html:text name="dynaFormulaire" property="inputField" />
funzione
se il campo di immissione è impostato su "this is a test", genera il codice HTML
<input type="text" name="inputField" value="questo è un test">
tag
<html:password name="dynaFormulaire" property="password" />
funzione
se il campo della password è "azerty", genera il codice HTML
<input type="password" name="password" value="azerty">
tag
<html:password name="dynaFormulaire" property="mdp" />
funzione
Se il campo "mdp" è "azerty", genera il codice HTML
<input type="password" name="password" value="azerty">
tag
<html:password name="dynaFormulaire" property="mdp" />
funzione
Se il campo "mdp" è "azerty", genera il codice HTML
<input type="password" name="password" value="azerty">
tag
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="comboValues"/>
</html:select>
funzione
se il campo a discesa è "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>
tag
<html:select name="dynaFormulaire" property="simpleList" size="3">
<html:options name="dynaFormulaire" property="simpleListValues"/>
</html:select>
funzione
se il campo simpleList è "simple1", genera il codice HTML
<select name="simpleList" size="3">
    <option value="simple0">simple0</option>
    <option value="simple1" selected="selected">simple1</option>
    <option value="simple2">simple2</option>
...
</select>
tag
<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
<html:options name="dynaFormulaire" property="multipleListValues"/>
</html:select>
funzione
Se il campo listeMultiple è l'array {"multiple0", "multiple2"}, genera il codice HTML
<select name="multipleList" 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>
tag
<html:hidden name="dynaFormulaire" property="secret"/>
funzione
se il campo segreto ha il valore "xxx", genera il codice HTML
<input type="hidden" name="secret" value="xxx">
tag
<html:submit>Invia</html:submit>
funzione
genera il codice HTML
<input type="submit" value="Invia">

L'ultima cosa da spiegare è il codice JavaScript incluso nella pagina JSP e associato ai due pulsanti [Clear] che deselezionano gli elementi selezionati nelle liste simpleList e multipleList:

<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 [Cancella], rivediamo come i vari elementi di un documento web vengono referenziati all'interno del codice JavaScript che utilizza quel documento:

Dati
Significato
documento
si riferisce all'intero documento web
document.forms
si riferisce all'insieme dei moduli definiti nel documento
document.forms[i]
si riferisce al modulo numero i nel documento
document.forms["formName"]
si riferisce al modulo <form> con l'attributo name impostato su "formName"
document.formName
si riferisce al modulo <form> con l'attributo name uguale a "formName"
document.[form].elements
si riferisce alla raccolta di elementi appartenenti al modulo designato dall'espressione [form]. Questa raccolta include tutti i tag <input>, <textarea> e <select> nel modulo designato.
document.[form].elements[i]
si riferisce all'elemento numero i di [form]
document.[form].elements["componentName"]
si riferisce all'elemento in [form] il cui attributo name è uguale a componentName
document.[form]. componentName
si riferisce all'elemento nel [form] il cui attributo name è uguale a componentName
document.[form].[component].value
si riferisce al valore del componente [component] del modulo [form] quando il suo codice HTML può avere un attributo value (<input>, <textarea>)
document.[form].[select].selectedIndex
si riferisce all'indice dell'opzione selezionata in un elenco. Può essere utilizzato sia per la lettura che per la scrittura. Impostando questa proprietà su -1 si deseleziona tutti gli elementi dell'elenco.
document.[form].[select].options
si riferisce all'array di opzioni associate a un tag <select>
document.[form].[select].options[i]
si riferisce all'opzione numero i del tag <select> specificato
document.[form].[select].options[i].selected
Un valore booleano che indica se l'opzione n. i dell'elemento [select] specificato è selezionata (true) o meno. Può essere utilizzato sia per la lettura che per la scrittura

Rivediamo il codice JavaScript per i due pulsanti:

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

Quando si clicca sul pulsante, viene eseguito il codice associato all'attributo "onclick". In questo caso, si tratta di codice inline. Molto spesso, scriviamo onclick="function(...)", dove function è una funzione definita all'interno di un tag <script language="javascript">...</script>. Cosa fa il codice sopra riportato? Analizziamo il codice del primo pulsante:

this
si riferisce al documento web in cui si trova il pulsante
this.form
si riferisce al modulo in cui si trova il pulsante
this.form.simpleList
si riferisce al componente simpleList del modulo
this.form.simpleList.selectedIndex
si riferisce all'indice dell'opzione selezionata in listeSimple. Impostando questa proprietà su -1 si deselezionano tutte le opzioni.

6.4.2. La vista confirmation.jsp

Ricordiamo che questa vista viene visualizzata dopo l'azione /confirmation, ovvero 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>

Qui introduciamo due nuove librerie di tag: struts-bean e struts-logic. La libreria struts-bean fornisce l'accesso agli oggetti nel contesto della richiesta, della sessione o dell'applicazione. La libreria struts-logic consente di implementare la logica di esecuzione utilizzando i tag. Nessuna di queste librerie è strettamente necessaria. Come abbiamo visto, una pagina JSP può:

  • recuperare oggetti dalla richiesta (request.getAttribute(...)), dalla sessione (session.getAttribute(...)) o dal contesto dell'applicazione
  • includere elementi dinamici nel codice HTML utilizzando variabili <%= variabile %>
  • contenere codice Java <% codice Java %>

L'inclusione di codice Java nelle pagine JSP infastidisce coloro che preferiscono una separazione rigorosa tra la logica dell'applicazione (codice Java) e la presentazione (uso dei tag). Ecco perché sono state create le librerie di tag.

Procederemo come abbiamo fatto per la vista formulaire.jsp** e spiegheremo ciascuno dei tag presenti nel codice di confirmation.jsp,** qualora non fossero già stati menzionati nella vista **formulaire.jsp**. Innanzitutto, si noti 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" %>

Si noti inoltre che queste tre librerie devono essere dichiarate nel file web.xml dell'applicazione. Commenteremo ora i tag nel documento formulaire.jsp:

tag
<bean:write name="dynaFormulaire" scope="session" property="opt"/>
funzione
scrive un valore nel flusso HTML corrente. Il tag bean:write supporta i seguenti attributi:
name: nome dell'oggetto da utilizzare
scope: ambito (request, session, context) in cui cercare questo oggetto
property: campo dell'oggetto designato da name la cui proprietà deve essere scritta. Questo campo può essere un oggetto di qualsiasi tipo. Verrà utilizzato il metodo toString dell'oggetto.
Qui viene scritto il valore del campo opt in dynaFormulaire. Il risultato sarà "yes" se l'utente ha selezionato il pulsante di opzione con l'attributo value="yes", oppure "no" se ha selezionato il pulsante di opzione con l'attributo value="no"
tag
<bean:write name="dynaFormulaire" scope="session" property="chk1"/>
funzione
scrive il valore del campo chk1 in dynaFormulaire. Il risultato sarà "on" se l'utente ha selezionato la casella, oppure "off" in caso contrario. Lo stesso vale per chk2 e chk3.
tag
<bean:write name="dynaFormulaire" scope="session" property="inputField"/>
funzione
scrive il valore del campo champSaisie in dynaFormulaire, ovvero il testo digitato dall'utente in quel campo. Lo stesso vale per mdp e boiteSaisie.
tag
<bean:write name="dynaFormulaire" scope="session" property="combo"/>
funzione
scrive il valore del campo a discesa in dynaFormulaire. Questo sarà l'attributo value dell'elemento <option> selezionato dall'utente.
tag
<bean:write name="dynaFormulaire" scope="session" property="listeSimple"/>
funzione
scrive il valore del campo simpleList in dynaForm. Conterrà l'attributo "value" dell'elemento <option> selezionato dall'utente, se ne è stato selezionato uno. In caso contrario, sarà una stringa vuota.
tag
            <logic:iterate id="choice" indexId="index" name="dynaForm" property="multipleList">
          <tr>
          <td>elenco multiplo[<bean:write name="index"/>]</td>
          <td><bean:write name="choice"/></td>
        </tr>
            </logic:iterate>
funzione
Qui introduciamo i tag logici. Abbiamo a che fare con un elenco a scelta multipla. Il valore del campo listeMultiple dell'oggetto dynaFormulaire è un array di stringhe. In Java, scriveremmo un ciclo. Il tag logic:iterate ci permette di eseguire lo stesso ciclo senza scrivere codice Java. In questo esempio, il tag logic:iterate ha i seguenti attributi:
name="dynaFormulaire": nome dell'oggetto da utilizzare
property="listeMultiple": nome della proprietà nell'oggetto specificato da name che contiene la collezione su cui eseguire l'iterazione nel ciclo. In questo caso, questa collezione è l'array di valori selezionati in listeMultiple. Questo array può essere vuoto.
id="choix": identificatore che designa l'elemento corrente dell'array ad ogni iterazione. Durante la prima iterazione, choix rappresenterà listeMultiple[0], durante la seconda listeMultiple[1] e così via.
indexID="index": identificatore che designa l'indice dell'elemento corrente dell'array ad ogni iterazione del ciclo. Durante la prima iterazione, index avrà il valore 0; durante la seconda, il valore 1; e così via.
Il codice HTML contenuto tra i tag <logic:iterate ...> e </logic:iterate> viene ripetuto per ciascun elemento della collezione designata dalla coppia (nome,proprietà). La parte dinamica di questo codice è la seguente:
          <td>multiple list[<bean:write name="index"/>]</td>
          <td><bean:write name="choice"/></td>
In base a quanto detto in precedenza, all'iterazione numero i (i>=0), il codice HTML generato è equivalente al seguente:
          <td>multiple list[<%=i%>]</td>
          <td><%=multipleList[i]%></td>
tag
    <html:link page="/affiche.do">
            Torna al modulo
        </html:link>
funzione
genera un link relativo al contesto dell'applicazione, il che elimina la necessità di conoscere il contesto. Il codice HTML generato da questo tag è il seguente:
<a href="/formulaire2/affiche.do">Torna al modulo</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 inviati tramite il pulsante [Invia] su 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 sovrascrivere uno dei metodi reset o validate di questa classe. In questo caso, non è necessario sovrascrivere il metodo validate poiché non viene eseguita alcuna convalida dei dati. Tuttavia, è necessario sovrascrivere il metodo reset. Questo perché i campi dell'oggetto DynaFormulaire riceveranno i loro valori dal modulo inviato dal client web. Tuttavia, alcuni campi potrebbero non ricevere un valore se non sono presenti nella richiesta. Ciò si verifica nei seguenti casi:

  • una casella di controllo che non è stata selezionata dall'utente
  • un elenco con più di un'opzione in cui nessuna è stata selezionata

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

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

Pertanto, se questi campi non ricevono un valore dalla query, mantengono il valore assegnato dal reset, che corrisponde allo stato del componente nel modulo convalidato dall'utente (casella di controllo deselezionata, elenco senza elementi selezionati).

Il codice per la classe DynaFormulaire, una sottoclasse di 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 checkboxes - value off
    set("chk1","off");
    set("chk2","off");
    set("chk2","off");
    // reset listeSimple - empty string
    set("listeSimple","");
     // reset listeMultiple - empty table
    set("listeMultiple",new String[]{});
  }
}

6.5.2. La classe InitFormAction

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

      <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 DynaForm. Il suo scopo è quello di fornire il contenuto per i tre elenchi a discesa del modulo: simpleList, multipleList e dropdownList. Questo contenuto viene fornito sotto forma di tre array, che sono proprietà dell'oggetto dynaForm:

        <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 gli array valuesCombo, valuesSingleList e valuesMultipleList sono stati inizializzati da InitFormAction, non è più necessario inizializzarli. Questo perché l'oggetto dynaForm viene inserito nella sessione e quindi mantiene il proprio valore attraverso i cicli richiesta-risposta. Ecco perché l'azione /init viene eseguita una sola volta. Il codice per InitFormAction è 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 {

     // prepares the form to be displayed

     // we put the information needed for the form in its bean
    DynaFormulaire formulaire = (DynaFormulaire) form;
    formulaire.set("valeursCombo", getValeurs(5, "combo"));
    formulaire.set("valeursListeSimple", getValeurs(7, "simple"));
    formulaire.set("valeursListeMultiple", getValeurs(10, "multiple"));
     // we give back
    return mapping.findForward("afficherFormulaire");
  } //execute

   // list of combo values
  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 estende la classe Action. Questo è obbligatorio.
  • Il controller Struts utilizza un oggetto Action tramite il suo metodo execute. Questo è quindi il 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 (l’attributo name dell’azione).
    • HttpServletRequest request: la richiesta del client
    • HttpServletResponse: la risposta al client
  • La classe InitFormulaireAction deve inizializzare il modulo dynaFormulaire. Questo viene passato al metodo execute come parametro del modulo ActionForm. Ricordiamo che dynaFormulaire è di tipo DynaFormulaire, una classe derivata dalla classe DynaActionForm, che a sua volta deriva dalla classe ActionForm.
  • Nel metodo execute, i valori vengono assegnati ai tre campi valeursCombo, valeursListeSimple e valeursListeMultiple utilizzando il metodo set della classe DynaActionForm. Per semplicità, questi valori sono array arbitrari. Si noti che il metodo set assegna un valore a un campo esistente. Non può essere utilizzato per creare nuovi campi. Questo è il motivo per cui è necessario definire i tre campi valeursCombo, valeursListeSimple e 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 delle directory dell'applicazione è la seguente:

  

Image

Image

Si noti che il file ApplicationResources.properties sopra riportato è richiesto dalla libreria di tag struts-bean. Sappiamo che questo file contiene i messaggi dell'applicazione, ai quali la libreria struts-bean può accedere. 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 vari componenti di un modulo HTML. Ora possiamo utilizzare moduli complessi nelle nostre applicazioni Struts.