4. Utilizzo di moduli dinamici
4.1. Dichiarazione del modulo dinamico
Abbiamo visto che Struts utilizza oggetti ActionForm per memorizzare i valori dei moduli HTML elaborati dai vari servlet dell'applicazione. Per ogni modulo della nostra applicazione, dobbiamo creare una classe derivata da ActionForm. Ciò può diventare rapidamente complicato poiché per ogni campo xx, dobbiamo scrivere due metodi: setXx e getXx. Struts offre la possibilità di utilizzare moduli
- la cui struttura è dichiarata nel file struts-config.xml all'interno della sezione <form-beans>
- , che vengono creati dinamicamente dall’ambiente Struts in base alla struttura dichiarata
Pertanto, la classe utilizzata per memorizzare i valori di nome ed età nell'applicazione strutspersonne potrebbe essere definita come segue:
<form-beans>
<form-bean name="frmPersonne" type="org.apache.struts.actions.DynaActionForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
Per ogni campo del modulo, definiamo un tag <form-property> con due attributi:
- name: il nome del campo
- type: il suo tipo Java
Poiché i valori di un modulo inviati da un client web sono stringhe, i tipi più comunemente utilizzati sono java.lang.String per i campi a valore singolo e java.lang.String[] per i campi a valori multipli (caselle di controllo con lo stesso nome, elenchi a selezione multipla, ecc.). La classe DynactionForm, come la classe ActionForm, ha un metodo validate che non fa nulla. Per far sì che verifichi la validità dei parametri del modulo, è necessario estenderla e scrivere il metodo validate autonomamente. La dichiarazione del modulo sarà quindi la seguente:
<form-beans>
<form-bean name="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
Dovremo scrivere noi stessi la classe istia.st.struts.personne.PersonneDynaForm.
4.2. Scrivere la classe DynaActionForm associata al modulo dinamico
In precedenza, abbiamo associato la classe istia.st.struts.personne.PersonneDynaForm al modulo (nome, età). Ora scriveremo questa classe:
package istia.st.struts.personne;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class PersonneDynaForm extends DynaActionForm {
// validation
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
// error management
ActionErrors erreurs = new ActionErrors();
// name must be non-empty
String nom = (String)this.get("nom");
if (nom == null || nom.trim().equals("")) {
erreurs.add("nomvide", new ActionError("personne.formulaire.nom.vide"));
}
// age must be non-empty
String age = (String)this.get("age");
if (age == null || age.trim().equals("")) {
erreurs.add("agevide", new ActionError("personne.formulaire.age.vide"));
}
else {
// age must be a positive integer
if (!age.matches("^\\s*\\d+\\s*$")) {
erreurs.add("ageincorrect", new ActionError("personne.formulaire.age.incorrect", age));
// return the list of errors
}
} //if
// return the error list
return erreurs;
}
}//class
È necessario tenere presente quanto segue:
- la classe deriva da DynaActionForm
- il metodo validate della classe DynaActionForm è stato riscritto. Quando viene eseguito dal controller Struts, viene costruito l'oggetto PersonneDynaForm. Esso contiene un dizionario le cui chiavi sono i campi del modulo name e age, e i cui valori sono i valori di tali campi. Per accedere a un campo all'interno dei metodi DynaActionForm, utilizzare il metodo Object get(String fieldName). Per impostare un valore per un campo, utilizzare il metodo void set(String fieldName, Object value). Fare riferimento alla definizione della classe DynaActionForm per una descrizione completa.
- Una volta recuperati i valori dei campi name e age del modulo, il metodo validate non è diverso da quello scritto quando il modulo era associato a un oggetto ActionForm.
4.3. La nuova classe FormAction
Il file di configurazione definisce la seguente azione /main:
...
<form-beans>
<form-bean name="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
....
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
type="istia.st.struts.personne.FormulaireAction"
>
<forward name="reponse" path="/reponse.do"/>
</action>
Questa definizione è identica a quella dell'applicazione strutspersonne. L'azione /main è implementata da un oggetto di tipo FormulaireAction. Questo oggetto riceveva i valori del modulo frmPersonne in un oggetto di tipo FormulaireBean. Ora li riceve in un oggetto di tipo PersonneDynaForm. Pertanto, la classe deve essere riscritta:
package istia.st.struts.personne;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import javax.servlet.ServletException;
import istia.st.struts.personne.PersonneDynaForm;
public class FormulaireAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException {
// we have a valid form, otherwise we wouldn't have got here
PersonneDynaForm formulaire=(PersonneDynaForm)form;
request.setAttribute("nom",formulaire.get("nom"));
request.setAttribute("age",formulaire.get("age"));
return mapping.findForward("reponse");
}//execute
}
È necessario tenere presente quanto segue:
- È necessario importare la classe PersonneDynaForm, che contiene i dati del modulo, per accedere alla sua definizione
- Il metodo execute recupera i valori dei parametri del modulo utilizzando il metodo [DynaActionForm].get.
Rispetto alla classe FormAction nell'applicazione strutspersonne, è cambiato solo il modo di accedere ai valori del modulo.
4.4. Distribuzione e test dell'applicazione strutspersonne1
4.4.1. Creazione del contesto
Abbiamo chiamato questa nuova applicazione strutspersonne1. Creiamo una nuova definizione nel file <tomcat>\conf\serveur.xml per Tomcat 4.x:
Una volta fatto questo, è necessario riavviare Tomcat. È possibile verificare la validità del contesto richiedendo l'URL:
http://localhost:8080/strutspersonne1/

4.4.2. Le viste
Copiare la cartella views dall'applicazione strutspersonne nella cartella dell'applicazione strutspersonne1. Le viste non sono cambiate.

4.4.3. Compilazione delle classi
Abbiamo due classi da creare: PersonneDynaForm e FormulaireAction, dove la seconda utilizza la prima. Possiamo crearle e compilarle utilizzando un progetto JBuilder:

4.4.4. La cartella WEB-INF
Copia la cartella WEB-INF dall'applicazione strutspersonne nella cartella dell'applicazione strutspersonne1. Alcuni file sono stati modificati:

Il file di configurazione struts-config.xml diventa 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="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
<action-mappings>
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
type="istia.st.struts.personne.FormulaireAction"
>
<forward name="reponse" path="/reponse.do"/>
</action>
<action
path="/erreurs"
parameter="/vues/erreurs.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/reponse"
parameter="/vues/reponse.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/formulaire"
parameter="/vues/formulaire.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
</action-mappings>
<message-resources parameter="ressources.personneressources"/>
</struts-config>
Questo file è identico a quello dell'applicazione strutspersonne, ad eccezione della definizione del modulo dinamico (sezione in riquadro).
Nella cartella WEB-INF/classes, inserire le classi compilate da JBuilder:

Nella cartella WEB-INF\classes\resources, inserisci il file dei messaggi. Non è cambiato.
personne.formulaire.nom.vide=<li>Vous devez indiquer un nom</li>
personne.formulaire.age.vide=<li>Vous devez indiquer un age</li>
personne.formulaire.age.incorrect=<li>L'âge [{0}] est incorrect</li>
errors.header=<ul>
errors.footer=</ul>

4.5. Test
Siamo pronti per i test. Di seguito sono riportati alcuni screenshot che il lettore è invitato a riprodurre.
Richiedi l'URL http://localhost:8080/strutspersonne1/formulaire.do:

Fare clic sul pulsante [Invia] senza compilare i campi:

Riprova inserendo un valore errato nel campo dell'età:

Otteniamo la seguente risposta:

Prova di nuovo, inserendo questa volta i valori corretti:

Riceviamo la seguente risposta:

4.6. Conclusione
L'uso di moduli dinamici semplifica la scrittura delle classi ActionForm responsabili della memorizzazione dei valori del modulo. Possiamo portare la gestione dei moduli a un livello superiore. Nell'applicazione strutspersonne1, abbiamo creato una classe PersonneDynaForm per convalidare i valori del modulo (nome, età). In pratica, alcune convalide si verificano frequentemente: campo non vuoto, campo che convalida una specifica espressione regolare, campo intero, campo data, ecc. Questo tipo di convalida standard può quindi essere specificato nel file di configurazione struts-config.html. Se tutte le convalide da eseguire sono "standard", non è necessario scrivere una classe per il modulo. Questo è ciò che esamineremo ora.