4. Gebruik van dynamische formulieren
4.1. Definitie van het dynamische formulier
We hebben gezien dat Struts ActionForm-objecten gebruikt om de waarden op te slaan van de HTML-formulieren die door de verschillende servlets van de applicatie worden verwerkt. Voor elk formulier in onze applicatie moeten we een klasse maken die is afgeleid van ActionForm. Dit kan al snel behoorlijk omslachtig worden, aangezien we voor elk veld xx twee methoden moeten schrijven: setXx en getXx. Struts biedt ons de mogelijkheid om formulieren te gebruiken
- waarvan de structuur is gedefinieerd in het bestand struts-config.xml in de sectie <form-beans>
- en die dynamisch door de Struts-omgeving worden aangemaakt op basis van de gedeclareerde structuur
De klasse die wordt gebruikt om de waarden ‘naam’ en ‘leeftijd’ van de Struts-toepassing ‘strutspersonne’ op te slaan, zou dus als volgt kunnen worden gedefinieerd:
<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>
Voor elk veld van het formulier definiëren we een <form-property>-tag met twee attributen:
- name: de naam van het veld
- type: het Java-type
Omdat de waarden van een formulier die door een webklant worden verzonden, tekenreeksen zijn, zijn de meest gebruikte typen java.lang.String voor velden met één waarde en java.lang.String[] voor velden met meerdere waarden (selectievakjes met dezelfde naam, lijsten met meerdere selectiemogelijkheden, ...). Zowel de klasse DynactionForm als de klasse ActionForm hebben een validate-methode die niets doet. Om de geldigheid van de formulierparameters te laten controleren, moet je deze klasse afleiden en zelf de validate-methode schrijven. De declaratie van het formulier ziet er dan als volgt uit:
<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>
De klasse istia.st.struts.personne.PersonneDynaForm moet door ons worden geschreven.
4.2. Het schrijven van de klasse DynaActionForm die gekoppeld is aan het dynamische formulier
Hierboven hebben we de klasse istia.st.struts.personne.PersonneDynaForm gekoppeld aan het formulier (naam, leeftijd). We schrijven nu deze klasse:
package istia.st.struts.personne;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class PersonneDynaForm extends DynaActionForm {
// validatie
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
// foutafhandeling
ActionErrors erreurs = new ActionErrors();
// de naam mag niet leeg zijn
String nom = (String)this.get("nom");
if (nom == null || nom.trim().equals("")) {
erreurs.add("nomvide", new ActionError("personne.formulaire.nom.vide"));
}
// de leeftijd mag niet leeg zijn
String age = (String)this.get("age");
if (age == null || age.trim().equals("")) {
erreurs.add("agevide", new ActionError("personne.formulaire.age.vide"));
}
else {
// de leeftijd moet een positief geheel getal zijn
if (!age.matches("^\\s*\\d+\\s*$")) {
erreurs.add("ageincorrect", new ActionError("personne.formulaire.age.incorrect", age));
// de lijst met fouten wordt weergegeven
}
} //if
// de lijst met fouten wordt weergegeven
return erreurs;
}
}//klasse
De volgende punten zijn van belang:
- de klasse is afgeleid van DynaActionForm
- de methode validate van de klasse DynaActionForm is herschreven. Wanneer deze wordt uitgevoerd door de Struts-controller, is het object PersonneDynaForm aangemaakt. Dit bevat een woordenboek met als sleutels de formuliervelden naam en leeftijd en als waarden de waarden van deze velden. Om toegang te krijgen tot een veld binnen de methoden van DynaActionForm, gebruikt men de methode Object get(String nomDuChamp). Als men een waarde aan een veld wil toekennen, kan men de methode void set(String nomDuChamp, Object waarde) gebruiken. Raadpleeg de definitie van de klasse DynaActionForm voor een volledige definitie.
- Zodra de waarden van de velden ‘naam’ en ‘leeftijd’ uit het formulier zijn opgehaald, verschilt de methode validate niet van de methode die was geschreven toen het formulier aan een object ActionForm was gekoppeld.
4.3. De nieuwe klasse FormulaireAction
Het configuratiebestand definieert de volgende actie /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>
Deze definitie is dezelfde als in de strutspersonne-applicatie. De actie /main wordt uitgevoerd door een object van het type FormulaireAction. Dit object ontving de waarden van het formulier frmPersonne in een object van het type FormulaireBean. Nu ontvangt het deze in een object van het type PersonneDynaForm. De klasse moet dus worden herschreven:
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 {
// het formulier is geldig, anders zouden we hier niet zijn gekomen
PersonneDynaForm formulaire=(PersonneDynaForm)form;
request.setAttribute("nom",formulaire.get("nom"));
request.setAttribute("age",formulaire.get("age"));
return mapping.findForward("reponse");
}//uitvoeren
}
De volgende punten zijn van belang:
- we moeten de klasse PersonneDynaForm importeren, die de gegevens van het formulier bevat, om toegang te krijgen tot de definitie ervan
- de methode `execute` haalt de waarden van de formulierparameters op met de methode `[DynaActionForm].get`.
Wat betreft de klasse FormulaireAction van de strutspersonne-applicatie is alleen de manier waarop toegang wordt verkregen tot de waarden van het formulier veranderd.
4.4. Implementatie en testen van de strutspersonne1-applicatie
4.4.1. Aanmaken van de context
We hebben deze nieuwe applicatie strutspersonne1 genoemd. We maken een nieuwe definitie aan in het Tomcat-bestand <tomcat>\conf\serveur.xml van Tomcat 4.x:
Zodra dit is gebeurd, moet Tomcat opnieuw worden opgestart. We kunnen de geldigheid van de context controleren door de URL op te vragen:
http://localhost:8080/strutspersonne1/

4.4.2. De weergaven
We kopiëren de map ‘vues’ van de applicatie ‘strutspersonne’ naar de map van de applicatie ‘strutspersonne1’. De weergaven zijn namelijk niet veranderd.

4.4.3. Compileren van de klassen
We moeten twee klassen aanmaken: PersonneDynaForm en FormulaireAction, waarbij de laatste gebruikmaakt van de eerste. We kunnen ze aanmaken en compileren met behulp van een JBuilder-project:

4.4.4. De map WEB-INF
We kopiëren de map WEB-INF van de applicatie strutspersonne naar de map van de applicatie strutspersonne1. Enkele bestanden veranderen:

Het configuratiebestand struts-config.xml ziet er nu als volgt uit:
<?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>
Dit bestand is identiek aan dat van de strutspersonne-applicatie, met uitzondering van de dynamische definitie van het formulier (omkaderd gedeelte).
In de map WEB-INF/classes plaatsen we de door JBuilder gecompileerde klassen:

In de map WEB-INF\classes\ressources plaatsen we het berichtbestand. Dit is niet gewijzigd.
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. Tests
We zijn klaar voor de tests. Hieronder vindt u enkele schermafbeeldingen die de lezer wordt verzocht na te maken.
We vragen om de URLhttp://localhost:8080/strutspersonne1/formulaire.do:

Gebruik de knop [Envoyer] zonder de velden in te vullen:

We proberen het opnieuw, maar er treedt een fout op in het veld ‘age’:

We krijgen het volgende antwoord:

We proberen het nog eens, dit keer met de juiste waarden:

We krijgen het volgende antwoord:

4.6. Conclusie
Het gebruik van dynamische formulieren maakt het eenvoudiger om klassen van het type ActionForm te schrijven die de waarden van de formulieren opslaan. We kunnen het beheer van formulieren nog iets verder vereenvoudigen. In de applicatie strutspersonne1 hebben we een klasse PersonneDynaForm aangemaakt om de geldigheid van de waarden (naam, leeftijd) van het formulier te controleren. In de praktijk komen bepaalde controles vaak voor: veld mag niet leeg zijn, veld dat aan een bepaalde reguliere expressie voldoet, geheel getalveld, datumveld, ... Dit soort standaardcontroles kan dan worden opgegeven in het configuratiebestand struts-config.html. Als alle uit te voeren controles „standaard“ zijn, hoeft er geen klasse meer voor het formulier te worden geschreven. Dat gaan we nu bekijken.