Skip to content

6. Formulieren HTML

Tot nu toe hebben we één enkel formulier gebruikt met slechts twee invoervelden. We stellen hier voor om een formulier te maken en te verwerken met behulp van de gebruikelijke grafische componenten (keuzerondjes, selectievakjes, invoervelden, keuzelijsten, lijsten).

6.1. De weergaven van de applicatie

De applicatie zal slechts twee weergaven hebben. De eerste toont een leeg formulier:

QZXW2HTMLP000547ZQX 1 - formulaire

Image

Deze eerste weergave, genaamd formulaire.jsp, stelt ons in staat om verschillende tags uit de struts-html-bibliotheek te implementeren. De gebruiker vult het formulier in:

Image

Met de knop [Envoyer] kun je de ingevoerde waarden bevestigen. Dit is de tweede weergave:

Image

In dit tweede scherm kunnen we twee andere tagbibliotheken gebruiken: struts-bean en struts-logic. Via de link [Retour au formulaire] kunnen we het formulier terugvinden zoals het is ingevuld. We komen dan terug bij het eerste scherm.

6.2. De architectuur van de applicatie

  • Het formulier (weergave 1) wordt weergegeven door een dynamisch Struts-object met de naam dynaFormulaire, waarvan het type is afgeleid van DynaActionForm. Het wordt weergegeven door de weergave formulaire.jsp.
  • De Struts-actie InitFormulaireAction heeft als doel de gegevens te verzamelen die nodig zijn voor de weergave van het formulier
  • het ingevulde formulier wordt verwerkt door een actie ForwardAction, die de aanvraag doorstuurt naar de tweede weergave confirmation.jsp. Deze zorgt ervoor dat de waarden van het formulier worden weergegeven.

6.3. De configuratie van de applicatie

6.3.1. Het bestand server.xml

De context van de applicatie krijgt de naam /formulaire2. We voegen daarom de volgende regel toe aan het Tomcat-bestand server.xml:

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

Zodra dit is gebeurd, starten we Tomcat eventueel opnieuw op, zodat de nieuwe context wordt overgenomen. We kunnen de geldigheid ervan controleren door de URL-http://localhost:8080/formulaire2 op te vragen:

Image

6.3.2. Het bestand web.xml

Het configuratiebestand web.xml van de applicatie ziet er als volgt uit:

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

Ten opzichte van de reeds besproken configuratiebestanden web.xml brengen we enkele wijzigingen aan:

  • we introduceren twee nieuwe tagbibliotheken: struts-bean en struts-logic. Deze zullen worden gebruikt in de weergave confirmation.jsp. De weergave formulaire.jsp zal daarentegen de bibliotheek struts-html gebruiken.

6.3.3. Het bestand struts-config.xml

Het bestand struts-config.xml ziet er 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="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>

Hierin zijn de drie grote secties te vinden:

  • de declaratie van de formulieren in de sectie <form-beans>
  • de declaratie van de acties in de sectie <action-mappings>
  • de declaratie van het bronnenbestand in <message-ressources>

6.3.4. De formulierobjecten (beans) van de applicatie

De objecten die worden gebruikt om de HTML-formulieren van de applicatie weer te geven, zijn objecten van het type ActionForm of daarvan afgeleide typen (DynaActionForm, DynaValidatorForm, ...). Ze worden ‘beans’ genoemd omdat hun opbouw voldoet aan de regels van JavaBeans. Er is slechts één formulier-bean in onze applicatie, genaamd dynaFormulaire en van een type dat is afgeleid van DynaActionForm. Deze wordt in de volgende situaties gebruikt:

  • het bevatten van de gegevens die nodig zijn voor de weergave van weergave nr. 1
  • het ophalen van de waarden uit het formulier van weergave nr. 1 wanneer de gebruiker het formulier verzendt (submit)
  • de gegevens bevatten die nodig zijn voor de weergave van weergave nr. 2

De structuur van de bean dynaFormulaire is nauw verbonden met het formulier van weergave nr. 1. Laten we dit eens bekijken:

Nr.
Type HTML
Rol
1
<input name="opt" type="radio" value="ja">
<input name="opt" type="radio" value="nee">
groep van onderling gekoppelde keuzerondjes (dezelfde naam)
2
<input name="chk1" type="radio" value="on">
<input name="chk2" type="radio" value="on">
<input name="chk3" type="radio" value="on">
groepen selectievakjes
(niet dezelfde naam)
3
<input type="text" name="champSaisie" >
een invoerveld
4
<input type="password" name="mdp">
een wachtwoordveld
5
<textarea name="boiteSaisie">...</textarea>
een invoerveld voor meerdere regels
6
<select name="combo" size="1">..</select>
een keuzelijst
7
<select name="listeSimple" size="3">..</select>
een lijst met één selectie
8
<select name="listeMultiple" size="3" multiple>..</select>
een lijst met meerdere selecties
9
<input type="button" value="Wissen"
onclick='effacerListe("listeSimple")'>
knop om de selectie van
de geselecteerde items in listeSimple (7)
10
<input type="button" value="Wissen"
onclick='lijstWissen("meervoudigeLijst")'>
knop om de selectie ongedaan te maken
de geselecteerde elementen in listeMultiple (8)
11
<input type="submit" value="Verzenden">
Verzendknop van het formulier
12
<input type="hidden" name="secret" value="...">
een verborgen veld

Laten we verschillende gevallen onderscheiden:

  1. het object dynaFormulaire wordt gebruikt om de waarden van het bovenstaande formulier HTML op te slaan, dat via de knop [Envoyer] wordt verzonden. Het moet dus dezelfde velden bevatten als in het formulier HTML. Het type van het veld wordt bepaald door de volgende regel:
  • als het veld HTML slechts één waarde bevat, dan is het veld van dynaFormulaire van het type java.lang.String
  • als het veld HTML meerdere waarden bevat, dan is het veld in dynaFormulaire van het type java.lang.String[]

In het bovenstaande formulier HTML kan alleen het veld listeMultiple aan meerdere waarden worden gekoppeld (de waarden die door de gebruiker zijn geselecteerd). Een eerste definitie van het object dynaFormulaire zou dus als volgt zijn:

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

Hoe wordt dynaFormulaire gevuld met de waarden uit het formulier HTML dat door de webclient is verzonden?

opt
Het veld 'opt' krijgt de waarde 'ja' als het veld HTML <input type="radio" name="opt" value="ja"> is aangevinkt, en de waarde 'nee' als het veld <input type="radio" name="opt" value="nee"> is aangevinkt.
chk1
het veld chk1 krijgt de waarde "on" als het veld HTML <input name="chk1" type="radio" value="1"> is aangevinkt, anders niets. In dat laatste geval behoudt het veld chk1 zijn vorige waarde.
chk2
idem
chk3
idem
champSaisie
het veld champSaisie krijgt de tekst die de gebruiker in het veld HTML <input type="text" name="champSaisie"> heeft ingevoerd. Deze tekst kan eventueel de lege tekenreeks zijn.
mdp
het veld mdp ontvangt de tekst die de gebruiker in het veld HTML <input type="password" name="mdp"> heeft ingevoerd. Deze tekst kan eventueel de lege tekenreeks zijn.
boiteSaisie
Het veld boiteSaisie ontvangt de tekst die de gebruiker in het veld HTML heeft ingevoerd <textarea name="boiteSaisie">...</textarea>. Deze tekst vormt één enkele tekenreeks, bestaande uit de door de gebruiker ingevoerde regels die van elkaar worden gescheiden door de tekenreeks "\r\n". De verkregen tekst kan eventueel de lege tekenreeks zijn.
combo
het comboveld ontvangt de door de gebruiker geselecteerde optie uit het veld HTML <select name="combo" size="1">..</select>. De geselecteerde optie is degene die in het comboveld verschijnt. Als de geselecteerde optie HTML van het type <option value="XX">YY</option> is, krijgt het comboveld de waarde "XX". Als de geselecteerde optie HTML van het type <option>YY</option> is, krijgt het keuzemenu de waarde "YY".
listeSimple
het veld listeSimple krijgt de door de gebruiker geselecteerde optie in het veld HTML <select name="listeSimple" size="..">..</select> indien er een is. Als er geen optie is geselecteerd, krijgt het veld listeSimple geen waarde en behoudt het zijn vorige waarde. De waarde die daadwerkelijk aan het veld listeSimple wordt toegewezen, volgt de regels die voor de keuzelijst zijn aangegeven.
listeMultiple
het veld listeMultiple van het type String[] krijgt de opties die de gebruiker heeft geselecteerd in het veld HTML <select name="listeMultiple" size=".." multiple>..</select> indien er een is. Als er geen opties zijn, krijgt de array listeMultiple geen waarden en blijft de inhoud ervan ongewijzigd. De waarden die daadwerkelijk aan de array listeMultiple worden toegewezen, volgen de regels die voor de keuzelijst zijn aangegeven.
secret
het veld secret krijgt de waarde XX uit het veld HTML <input type="hidden" name="secret" value="XX">. Deze tekst kan eventueel de lege tekenreeks zijn.
  1. Het object dynaFormulaire wordt gebruikt om de initiële inhoud van weergave nr. 1 te bepalen. De waarden van de voorgaande velden worden voor de volgende doeleinden gebruikt:
opt
moet de waarde „ja” of „nee” hebben, zodat de browser weet welk keuzerondje moet worden aangevinkt
chk1
als chk1 de waarde "on" heeft, wordt het selectievakje aangevinkt; anders niet
chk2
idem
chk3
idem
champSaisie
de waarde van het veld wordt weergegeven in het invoerveld champSaisie
mdp
de waarde van het veld wordt weergegeven in het invoerveld mdp
boiteSaisie
de waarde van het veld wordt weergegeven in het invoerveld boiteSaisie
combo
de waarde van dit veld geeft aan welk element uit de keuzelijst moet worden geselecteerd wanneer het formulier wordt weergegeven
listeSimple
idem
listeMultiple
de waarden in de tabel listeMultiple geven aan welke elementen uit de meervoudige lijst moeten worden geselecteerd wanneer het formulier wordt weergegeven
secret
de waarde van het veld wordt toegewezen aan het attribuut 'value' van het veld HTML secret.

Weergave nr. 1 heeft nog meer informatie nodig:

  • de lijst met waarden die in de keuzelijst moeten worden weergegeven
  • de lijst met waarden die in de lijst listeSimple moeten worden weergegeven
  • de lijst met waarden die in de lijst listeMultiple moeten worden weergegeven

Er zijn verschillende manieren om deze informatie aan de view te verstrekken. Tabellen die in de aan de view doorgegeven query worden opgenomen, zouden bijvoorbeeld volstaan. Hier plaatsen we deze tabellen in de 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>            

Het formulier dynaFormulaire wordt geïnitialiseerd door de actie /init, die een van Action afgeleid object met de naam InitFormulaireAction aanroept. Dit object zorgt ervoor dat de drie tabellen die nodig zijn voor de weergave van de drie lijsten worden aangemaakt en in de bean dynaFormulaire worden geplaatst. Het configuratiebestand geeft deze bean een bereik dat gelijk is aan de sessie. Dit betekent dat de Struts-controller deze bean in de sessie zal plaatsen. We hoeven hem dus niet opnieuw te genereren tussen twee verzoek-antwoordcycli. De actie /init wordt dan ook slechts één keer aangeroepen.

  1. Het object dynaFormulaire wordt ook gebruikt om de inhoud van weergave nr. 2 te leveren. Deze weergave beperkt zich tot het weergeven van de waarden.

6.3.5. De acties van de applicatie

De acties worden uitgevoerd door objecten van het type Action of daarvan afgeleide typen. De configuratie van de acties vindt plaats binnen de tags <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>

Merk op dat er niet altijd een formulier aan een actie is gekoppeld. Dit is hierboven het geval bij de actie /affiche. Voordat we elke actie in detail bespreken, gaan we eerst even terug op de werking van het gekoppelde actie-formulierpaar binnen een <action>-tag:

  • een actie begint met een verzoek van een webclient en eindigt met het verzenden van een antwoordpagina. Dit is de vraag-antwoordcyclus van de webclient-server. Het verzoek wordt ontvangen door de Struts-controller van het type ActionServlet of een afgeleide daarvan. Deze controller verzendt ook het antwoord.
  • De formulier-bean van het type ActionForm of een afgeleide daarvan wordt aangemaakt als deze nog niet bestaat. De controller controleert of hij een object met de naam name kan vinden in het bereik dat wordt aangegeven door scope. Zo ja, dan gebruikt hij dit. Zo niet, dan maakt hij het aan en plaatst het in het bereik dat wordt aangegeven door scope, gekoppeld aan het attribuut dat wordt aangegeven door name.

In het voorbeeld van de actie /init zal de controller bijvoorbeeld een request.getSession().getAttribute("dynaFormulaire") uitvoeren om te controleren of dynaFormulaire al is aangemaakt of niet. Als dat niet het geval is, zal hij het aanmaken en in de sessie plaatsen met een instructie zoals request.getSession().setAttribute("dynaFormulaire", new DynaFormulaire(...)).

  • De controller zoekt ook naar een Action-object van het type dat wordt aangegeven door het type-attribuut. Als hij het niet vindt, maakt hij het aan; anders gebruikt hij het.
  • De methode reset van de formulier-bean wordt aangeroepen. Deze wordt, behalve bij de eerste aanmaak, hergebruikt. Hij bevat dan gegevens die men wellicht wil „opschonen”. Dit gebeurt in de methode reset van de bean ActionForm of een afgeleide daarvan.
  • Als de actie het doel is van een verzonden formulier, worden de formulierwaarden die in het verzoek van de client staan, gekopieerd naar de velden met dezelfde naam in de formulier-bean. Merk op dat de methode `reset` is aangeroepen vóór deze kopieerbewerking.
  • Als in de configuratie het attribuut `validate="true"` is opgegeven, wordt de methode `validate` van de formulier-bean aangeroepen. Deze moet vervolgens de gegevens van de bean controleren. Deze controle vindt meestal alleen plaats wanneer het formulier zojuist nieuwe gegevens heeft ontvangen via een verzonden formulier en men de geldigheid van deze gegevens wil controleren. Deze methode retourneert een eventuele lijst met fouten aan de controller in een object ActionErrors.
  • Als het object ActionErrors niet leeg is, laat de controller de weergave zien die is opgegeven door het attribuut input van de actie.
  • Als er geen gegevensvalidatie is aangevraagd of als deze succesvol is verlopen, laat de controller de methode `execute` uitvoeren van het object van het type `Action` of een afgeleid type dat aan de huidige actie is gekoppeld. In deze methode wordt het verzoek van de webclient verwerkt. De methode `execute` retourneert een object `ActionForward` dat is geïndexeerd met sleutels van het type tekenreeks. Deze sleutels zijn de sleutels die zijn gedeclareerd door de forward-tags van de geconfigureerde actie. In ons voorbeeld heeft de actie /init één enkele forward-tag. Deze koppelt de sleutel "afficherFormulaire" aan de weergave formulaire.jsp.
  • De controller laat de weergave weergeven waaraan de ontvangen sleutel is gekoppeld. Deze weergave kan in feite een actie zijn, in welk geval het voorgaande proces wordt herhaald.

De actie /init

        <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>
  • De actie /init vindt normaal gesproken één keer plaats tijdens de eerste vraag-antwoordcyclus wanneer de gebruiker het URL-http://localhost:8080/formulaire2/init.do opvraagt
  • het object dynaFormulaire wordt aangemaakt of hergebruikt. Het wordt opgehaald (hergebruik) of geplaatst (aanmaken) in de sessie, zoals bepaald door het scope-attribuut.
  • De methode reset wordt aangeroepen. Wat moet deze doen? Normaal gesproken worden de velden van het object ActionForm teruggezet naar hun standaardwaarden. Alleen in dit geval doen we dat niet, omdat het object dynaFormulaire in de sessie wordt geplaatst (scope="session"). De velden van dynaFormulaire moeten dus hun waarden behouden. Wat zijn deze waarden bij de eerste aanmaak van het object dynaFormulaire? Er zijn twee gevallen:
  • het veld heeft een beginwaarde die in het configuratiebestand is opgegeven:
            <form-property name="opt" type="java.lang.String" initial="non"/>

In dit geval zal de Struts-controller dit veld met deze beginwaarde aanmaken.

  • het veld heeft geen initiële waarde volgens de configuratie: dan gelden de initialisatieregels van Java. Over het algemeen krijgen numerieke velden de waarde nul, tekenreeksen de lege tekenreeks en andere objecten de waarde null.

Laten we eens kijken naar de initiële configuratie van 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>            

De beginwaarden van de velden van dynaFormulaire na het aanmaken ervan zijn als volgt:

Veld
Standaardwaarde
opt
"nee"
chk1, chk2, chk3
lege tekenreeks
champSaisie
lege tekenreeks
mdp
lege tekenreeks
boiteSaisie
lege tekenreeks
combo
lege tekenreeks
listeSimple
lege tekenreeks
listeMultiple
tabel met lege tekenreeksen
secret
"xxx"
valeursCombo, listeSimple, listeMultiple
array van lege strings
  • men zou kunnen veronderstellen dat de reset-methode van dynaFormulaire waarden toekent aan de drie tabellen die de drie lijsten van de weergave formulaire.jsp moeten vullen. Dat zou hier mogelijk zijn, omdat de gegevens van deze drie arrays willekeurig worden gegenereerd. Het meest gebruikelijke geval is echter dat deze gegevens afkomstig zijn uit het applicatiemodel, de M van MVC. Om het voorbeeld niet te ingewikkeld te maken, kiezen we hier voor een tussenoplossing, waarbij we deze waarden laten genereren door de actie InitFormulaireAction, dus door de C van MVC.
  • Het is niet verplicht om een reset-methode te schrijven in dynaFormulaire, aangezien de klasse ActionForm, waarvan deze is afgeleid, al een dergelijke methode heeft die niets doet (geen initialisaties).
  • Zodra de reset-methode van dynaFormulaire is aangeroepen, controleert de controller het attribuut validate van de actie. Hier heeft het de waarde "false". De validate-methode van dynaFormulaire wordt niet aangeroepen.
  • Het object InitFormulaireAction wordt aangemaakt of hergebruikt als het al bestond, en de methode `execute` ervan wordt aangeroepen. Deze methode wijst willekeurige waarden toe aan de drie arrays van dynaFormulaire: valeursCombo, valeursListeSimple en valeursListeMultiple. De methode retourneert een ActionForward met sleutel "afficherFormulaire".
  • De controller laat de weergave /vues/formulaire.jsp weergeven, die via een forward-tag van de actie /init is gekoppeld aan de sleutel "afficherFormulaire".

De actie /confirmation

      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • De actie /confirmation vindt plaats wanneer de gebruiker op de knop [Envoyer] in weergave nr. 1 drukt. De browser 'verzendt' vervolgens het door de gebruiker ingevulde formulier naar de Struts-controller.
  • het object dynaFormulaire wordt in de sessie opgenomen
  • en de methode `reset` ervan wordt aangeroepen. Zodra deze methode is aangeroepen, kopieert de Struts-controller de waarden van de formuliervelden die door de client zijn verzonden naar de velden met dezelfde naam in dynaFormulaire. Laten we de lijst met velden van dit laatste object nog eens bekijken en zien hoe deze kopieeractie verloopt:
Veld
Bijbehorende code HTML
Waarde van het veld
na het kopiëren van de formulierwaarden
opt
<input type="radio" name="opt" value="ja">Ja
<input type="radio" name="opt" value="nee" checked="checked">Nee
- "ja" of "nee", afhankelijk van de geselecteerde keuzeknop
chk1
<input type="checkbox" name="chk1" value="on">
- "on" als het selectievakje chk1 is aangevinkt
- behoudt zijn vorige waarde als het vakje chk1 niet is aangevinkt
chk2
<input type="checkbox" name="chk2" value="on">
- "on" als het selectievakje chk2 is aangevinkt
- behoudt de vorige waarde als het selectievakje chk2 niet is aangevinkt
chk3
<input type="checkbox" name="chk2" value="on">
- "on" als het selectievakje chk3 is aangevinkt
- behoudt de vorige waarde als het vakje chk3 niet is aangevinkt
champSaisie
<input type="text" name="champSaisie" value="">
- waarde die door de gebruiker is ingevoerd in champSaisie
mdp
<input type="password" name="mdp" value="">
- waarde die de gebruiker heeft ingevoerd in mdp
boiteSaisie
<textarea name="boiteSaisie"></textarea>
- waarde die de gebruiker heeft ingevoerd in boiteSaisie
combo
<select name="combo">...</select>
- door de gebruiker geselecteerde waarde in combo
listeSimple
<select name="listeSimple" size="3">...</select>
- door de gebruiker geselecteerde waarde in listeSimple
listeMultiple
<select name="listeMultiple" multiple="multiple" size="5">
- array van strings met de door de gebruiker geselecteerde waarden in listeMultiple
secret
<input type="hidden" name="secret" value="xxx">
- "xxx".

Er is een probleem met velden die niet noodzakelijkerwijs een waarde ontvangen in het verzoek dat door de browser wordt verzonden. Dit is het geval bij de selectievakjes chk1 tot en met chk3 en bij de twee lijsten listeSimple en listeMultiple. In dit geval behouden deze velden hun vorige waarde, die tijdens de vorige vraag-antwoordcyclus is vastgelegd.

Laten we bijvoorbeeld eens kijken naar het selectievakje chk1 en aannemen dat de gebruiker dit vakje in de vorige verzoek-antwoordcyclus had aangevinkt. De browser had toen in de parameterreeks van zijn verzoek de informatie chk1="on" verzonden. De ontwikkelaar heeft daarom de waarde "on" toegewezen aan het veld chk1 van dynaFormulaire. Laten we nu aannemen dat de gebruiker in de huidige cyclus het selectievakje chk1 niet aanvinkt. In dat geval verstuurt de browser in de parameterreeks van het nieuwe verzoek niet iets als chk1="off", maar verstuurt hij helemaal niets. Daardoor behoudt het veld chk1 van dynaFormulaire zijn waarde "on" en heeft het dus een waarde die niet overeenkomt met die van het door de gebruiker gevalideerde formulier. We gebruiken de reset-methode van dynaFormulaire om dit probleem op te lossen. In deze methode zetten we de drie velden chk1, chk2 en chk3 op "off". In ons voorbeeld van chk1: ofwel vinkt de gebruiker

  • het selectievakje chk1 aanvinkt. Dan stuurt de browser de informatie chk1="on" en wordt het veld chk1 van dynaFormulaire op "on" gezet
  • het vakje chk1 niet aanvinkt. Dan stuurt de browser geen waarde voor het veld chk1, dat zijn vorige waarde "off" behoudt. In beide gevallen is de waarde die is opgeslagen in het veld chk1 van dynaFormulaire correct.

Het probleem is hetzelfde voor beide lijsten listeSimple en listeMultiple. Als er in deze lijsten geen optie is geselecteerd, zullen ze niet in de queryparameters voorkomen en behouden ze dus hun eerdere waarden. In de reset-methode van dynaFormulaire zullen we listeSimple opnieuw initialiseren met een lege tekenreeks en listeMultiple met een array van tekenreeksen met lengte 0.

  • Zodra de reset-methode van dynaFormulaire is aangeroepen, kopieert de controller de informatie die hem in de verzoek van de klant is verzonden, naar de velden van dynaFormulaire
  • Er wordt een object ForwardAction aangemaakt of hergebruikt en de methode `execute` ervan wordt aangeroepen. ForwardAction is een vooraf gedefinieerde klasse die een ActionForward-object retourneert dat verwijst naar de weergave die is gedefinieerd door het "parameter"-attribuut van de actie, in dit geval /vues/confirmation.jsp.
  • De controller verstuurt deze weergave. De cyclus is voltooid.

De actie /toont

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • De actie /affiche wordt geactiveerd door op de link [Retour vers le formulaire] in weergave nr. 2 te klikken.
  • Hier is er geen formulier gekoppeld aan de actie. We gaan dus onmiddellijk over tot de uitvoering van de methode `execute` van een object `ForwardAction`, dat een object `ActionForward` zal retourneren dat verwijst naar de weergave `/vues/formulaire.jsp`.

6.3.6. Het berichtenbestand van de applicatie

Het derde gedeelte van het bestand struts-config.xml is het berichtenbestand:

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

Het bestand ApplicationResources.properties wordt in WEB-INF/classes geplaatst. Het zal leeg zijn. Ook al is het leeg, het moet toch in het configuratiebestand worden vermeld, anders genereert de Struts-bean-tagbibliotheek, die we straks zullen bespreken, een foutmelding. Deze bibliotheek wordt gebruikt door de weergave confirmation.jsp.

6.4. De code van de weergaven

6.4.1. De weergave formulaire.jsp

Ter herinnering: deze weergave wordt in twee gevallen weergegeven:

  • bij het aanroepen van de actie /init tijdens de eerste verzoek-antwoordcyclus
  • bij het aanroepen van de actie /affiche tijdens de volgende cycli

De code van de weergave formulaire.jsp is als volgt:

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

Deze pagina JSP maakt gebruik van tags uit de struts-html-bibliotheek. Ter herinnering: om een tagbibliotheek te gebruiken, moet u:

  • deze in het bestand web.xml van de applicatie te declareren met een <tag-lib>-tag
  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  • plaats de code van deze bibliotheek ergens in de mappenstructuur van de applicatie, hier WEB-INF/struts-html.tld
  • Geef aan het begin van de pagina's JSP die deze bibliotheek gebruiken aan dat deze wordt gebruikt:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

De weergave formulaire.jsp maakt gebruik van tags die we nu zullen toelichten:

balise
<body background="<html:rewrite page="/images/standard.jpg"/>">
traduction HTML
<body background="/formulaire2/images/standard.jpg">
explication
Met de tag html:rewrite kun je de naam van de applicatie in URL omzeilen. Deze tag heeft één attribuut:
page
URL moet worden herschreven
Zoals hierboven weergegeven, hoeft de code van het attribuut 'background' niet te worden herschreven als we besluiten de applicatie 'formulaire3' te noemen. De tag html:rewrite genereert de nieuwe code 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
Met de tag `html:form` kan de tag `HTML form` worden gegenereerd. Deze tag heeft verschillende attributen:
action
Struts-actie waarnaar het formulier moet worden verzonden – moet overeenkomen met een van de acties die zijn gedefinieerd in struts-config.xml
name
optioneel – naam van de bean ActionForm of een afgeleide daarvan waarin de waarden van het verzonden formulier moeten worden geplaatst of uitgelezen. Als dit attribuut ontbreekt, wordt het formulier gebruikt dat is gekoppeld aan de actie die is gedefinieerd door het attribuut action. Deze informatie is te vinden in het configuratiebestand (attribuut name van de actie).
type
optioneel – Java-klasse die voor het formulier moet worden geïnstantieerd. Als dit attribuut ontbreekt, wordt de klasse gebruikt die is gekoppeld aan de actie die is gedefinieerd door het attribuut action. Deze informatie is te vinden in het configuratiebestand (attribuut type van de actie).
We zien dat de gegenereerde code HTML standaard de methode POST gebruikt. In dezelfde code HTML is de URL van de actie herschreven, zodat deze wordt voorafgegaan door de naam van de applicatie en wordt gevolgd door .do.
balise
<html:radio name="dynaFormulaire" property="opt" value="ja">Ja</html:radio>
traduction HTML
<input type="radio" name="opt" value="oui">
explication
De tag html:radio wordt gebruikt om de tag HTML <input type="radio" ...> te genereren. Deze tag ondersteunt verschillende attributen:
name
optioneel - naam van de bean ActionForm of een afgeleide daarvan waarin de waarde van het veld moet worden geplaatst of uitgelezen. Als dit attribuut ontbreekt, wordt het formulier gebruikt dat is gekoppeld aan de tag <html:form>.
property
naam van het veld in de formulier-bean die is gekoppeld aan de keuzeknop, voor zowel lezen als schrijven.
value
optioneel – waarde die aan het veld HTML moet worden toegekend
De tekst tussen de begin- en eindtag is de tekst die naast de keuzeknop wordt weergegeven.
balise
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
traduction HTML
<input type="checkbox" name="chk1" value="on">
explication
De tag html:checkbox wordt gebruikt om de tag HTML <input type="checkbox" ...> te genereren. Deze tag ondersteunt verschillende attributen:
name
optioneel - naam van de bean ActionForm of een afgeleide daarvan waarin de waarde van het veld moet worden geplaatst of uitgelezen. Als dit attribuut ontbreekt, wordt het formulier gebruikt dat aan de tag <html:form> is gekoppeld.
property
naam van het veld in de formulier-bean die is gekoppeld aan het selectievakje, voor zowel lezen als schrijven.
value
optioneel – waarde die aan het veld moet worden toegekend HTML
De tekst tussen de begin- en eindtag is de tekst die naast het selectievakje wordt weergegeven.
balise
<html:text name="dynaFormulaire" property="champSaisie" />
traduction HTML
<input type="text" name="champSaisie" value="">
explication
De tag html:text wordt gebruikt om de tag HTML <input type="text" ...> te genereren. Deze tag ondersteunt verschillende attributen:
name
optioneel - naam van de bean ActionForm of een afgeleide daarvan waarin de waarde van het veld moet worden geplaatst of uitgelezen. Als dit attribuut ontbreekt, wordt het formulier gebruikt dat aan de tag <html:form> is gekoppeld.
property
naam van het veld in de formulier-bean die is gekoppeld aan het invoerveld voor lezen en schrijven.
value
optioneel - waarde die moet worden ingevuld in veld HTML
balise
<html:password name="dynaFormulaire" property="mdp" />
traduction HTML
<input type="password" name="mdp" value="">
explication
De tag html:password wordt gebruikt om de tag HTML <input type="password" ...> te genereren. Deze tag ondersteunt verschillende attributen:
balise
<html:textarea name="dynaFormulaire" property="boiteSaisie" />
traduction HTML
<textarea name="boiteSaisie"></textarea>
explication
De tag html:textarea wordt gebruikt om de tag HTML <textarea>...</textarea> te genereren. Deze tag ondersteunt verschillende attributen:
name
optioneel - naam van de bean ActionForm of een afgeleide daarvan waarin de waarde van het veld moet worden geplaatst of uitgelezen. Als dit attribuut ontbreekt, wordt het formulier gebruikt dat aan de tag <html:form> is gekoppeld.
property
naam van het veld in de formulier-bean die is gekoppeld aan het wachtwoordveld, zowel voor lezen als schrijven.
value
optioneel – waarde die aan het veld moet worden toegekend HTML
balise
<html:select name="dynaFormulaire" property="combo">....</html:select>
traduction HTML
<select name="combo">...</select>
explication
De html:select-tag wordt gebruikt om de tag HTML <select>...</select> te genereren. Deze tag ondersteunt verschillende attributen:
name
optioneel - naam van de bean ActionForm of een afgeleide daarvan waarin de waarde van het veld moet worden geplaatst of uitgelezen. Als dit attribuut ontbreekt, wordt het formulier gebruikt dat is gekoppeld aan de tag <html:form>.
property
naam van het veld in de formulier-bean die is gekoppeld aan het invoerveld voor lezen en schrijven.
value
optioneel – waarde die moet worden toegekend aan het veld HTML. De optie in de keuzelijst met deze waarde wordt geselecteerd.
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
De HTML-tag:options wordt gebruikt om de tags HTML <option>...</option> te genereren binnen een tag HTML <select>. Er zijn verschillende manieren om aan te geven hoe de waarden voor de select-lijst moeten worden gevonden. Hier hebben we de attributen name en property gebruikt:
name
optioneel – naam van de bean ActionForm of een afgeleide daarvan waarin de waarde van het veld moet worden geplaatst of uitgelezen. Als dit attribuut ontbreekt, wordt het formulier gebruikt dat is gekoppeld aan de tag <html:form>.
property
naam van het veld in de formulier-bean dat de waarden van de select-lijst bevat. Dit moet een array van tekenreeksen zijn.

De twee andere lijsten worden op dezelfde manier gegenereerd als de vorige:

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

Hierboven wordt een size-attribuut opgegeven dat niet gelijk is aan 1, om een lijst te krijgen in plaats van een keuzelijst.

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

Hierboven wordt het attribuut multiple=&quot;true&quot; opgegeven om een lijst met meervoudige selectie te krijgen.

balise
<html:hidden name="dynaFormulaire" property="secret"/>
traduction HTML
<input type="hidden" name="secret" value="xxx">
explication
de tag html:hidden wordt gebruikt om de tag HTML <input type="hidden" ...> te genereren.
name
optioneel - naam van de bean ActionForm of een afgeleide daarvan, waarin de waarde van het veld moet worden geplaatst of uitgelezen. Als dit attribuut ontbreekt, wordt het formulier gebruikt dat aan de tag <html:form> is gekoppeld.
property
naam van het veld in de formulier-bean die aan het verborgen veld is gekoppeld. De waarde "xxx" die aan het verborgen veld HTML is toegekend, is afkomstig uit de definitie van het formulier in het configuratiebestand. Daarin is een beginwaarde "xxx" gedefinieerd voor het verborgen veld.

Om het verband tussen de weergave formulaire.jsp en de bean dynaFormulaire die deze in het geheugen vertegenwoordigt goed te begrijpen, moet men bedenken dat de bean dynaFormulaire zowel voor lezen als voor schrijven wordt gebruikt:

De verzoek wordt verzonden wanneer de gebruiker op de knop [Envoyer] in het formulier klikt. De browser ‘verzendt’ dan het formulier HTML naar de actie /confirmation. We hebben al uitgelegd wat er dan gebeurt, en met name dat de velden van dynaFormulaire de waarden zullen ontvangen van de velden met dezelfde naam in het formulier HTML.

Wat gebeurt er wanneer de controller de weergave van de view formulaire.jsp opvraagt als reactie op een verzoek? Laten we de tags één voor één nog eens bekijken:

balise
<body background="<html:rewrite page="/images/standard.jpg"/>">
fonction
genereert de code HTML
<body background="/formulaire2/images/standard.jpg">
balise
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
</html:form>
fonction
genereert de code HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
balise
<html:radio name="dynaFormulaire" property="opt" value="ja">Ja</html:radio>
<html:radio name="dynaFormulaire" property="opt" value="nee">Nee</html:radio>
fonction
Als het veld opt van dynaFormulaire de waarde "ja" heeft, genereer dan de code 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
Als de velden chk1 en chk3 van dynaFormulaire de waarde "on" hebben en het veld chk2 de waarde "off", genereer dan de code 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
als het veld champSaisie de waarde "dit is een test" heeft, genereer dan de code HTML
<input type="text" name="champSaisie" value="ceci est un essai">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
als het veld mdp de waarde "azerty" heeft, genereert het de code HTML
<input type="password" name="mdp" value="azerty">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
als het veld mdp de waarde "azerty" heeft, genereert het de code HTML
<input type="password" name="mdp" value="azerty">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
als het veld mdp de waarde "azerty" heeft, genereert het de code HTML
<input type="password" name="mdp" value="azerty">
balise
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="valeursCombo"/>
</html:select>
fonction
als het combo-veld de waarde "combo2" heeft, genereer dan de code 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
als het veld listeSimple de waarde "simple1" heeft, genereer dan de code 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
als het veld listeMultiple de array {"multiple0","multiple2"} is, genereer dan de code 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
als het veld 'secret' de waarde "xxx" heeft, genereer dan de code HTML
<input type="hidden" name="secret" value="xxx">
balise
<html:submit>Verzenden</html:submit>
fonction
genereer de code HTML
<input type="submit" value="Envoyer">

Het laatste wat nog uitgelegd moet worden, is de JavaScript-code die is opgenomen in de pagina JSP en gekoppeld is aan de twee knoppen [Effacer], waarmee de geselecteerde elementen in de lijsten listeSimple en listeMultiple worden gedeselecteerd:

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

De tag

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

levert de volgende code HTML op:

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

Om de JavaScript-code te begrijpen die verband houdt met de knoppen [Effacer], is het nuttig om even te herhalen hoe de verschillende elementen van een webdocument worden aangeduid in JavaScript-code die dit document gebruikt:

Gegevens
Betekenis
document
verwijst naar het volledige webdocument
document.forms
verwijst naar de verzameling formulieren die in het document zijn gedefinieerd
document.forms[i]
verwijst naar formulier nr. i van het document
document.forms["nomFormulaire"]
verwijst naar het formulier <form> met het attribuut name gelijk aan "nomFormulaire"
document.nomFormulaire
verwijst naar het formulier <form> met het attribuut name gelijk aan "nomFormulaire"
document.[formulaire].elements
verwijst naar de verzameling van de elementen die deel uitmaken van het formulier dat wordt aangeduid door de uitdrukking [formulaire]. Deze verzameling omvat alle tags <input>, <textarea> en <select> van het betreffende formulier.
document.[formulaire].elements[i]
verwijst naar element nr. i van [formulaire]
document.[formulaire].elements["nomComposant"]
verwijst naar het element van [formulaire] waarvan het attribuut name gelijk is aan nomComposant
document.[formulaire]. nomComposant
verwijst naar het element van [formulaire] waarvan het attribuut name gelijk is aan nomComposant
document.[formulaire].[composant].value
verwijst naar de waarde van de component [composant] van het formulier [formulaire] wanneer de code HTML daarvan een value-attribuut kan hebben (<input>, <textarea>)
document.[formulaire].[select].selectedIndex
verwijst naar de index van de geselecteerde optie in een lijst. Wordt gebruikt voor zowel lezen als schrijven. Door deze eigenschap op -1 te zetten, worden alle elementen in de lijst gedeselecteerd.
document.[formulaire].[select].options
geeft de tabel aan met opties die gekoppeld zijn aan een <select>-tag
document.[formulaire].[select].options[i]
verwijst naar optie nr. i van de aangegeven <select>-tag
document.[formulaire].[select].options[i].selected
booleaanse waarde die aangeeft of optie nr. i van de aangegeven tag [select] is geselecteerd (true) of niet. Kan zowel voor lezen als schrijven worden gebruikt

Laten we nog eens kijken naar de JavaScript-code van de twee knoppen:

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

Bij het klikken op de knop wordt de code uitgevoerd die is gekoppeld aan het attribuut "onclick". In dit geval is het inline-code. Meestal schrijft men onclick="functie(...)", waarbij functie een functie is die is gedefinieerd binnen een <script language="javascript">...</script>-tag. Wat doet de bovenstaande code? Laten we de code van de eerste knop eens bekijken:

this
verwijst naar het webdocument waarin de knop zich bevindt
this.form
verwijst naar het formulier waarin de knop zich bevindt
this.form.listeSimple
verwijst naar de component listeSimple van het formulier
this.form.listeSimple.selectedIndex
verwijst naar de index van de geselecteerde optie in listeSimple. Als u deze eigenschap op -1 zet, worden alle opties gedeselecteerd.

6.4.2. De weergave confirmation.jsp

Ter herinnering: deze weergave wordt getoond na afloop van de actie /bevestiging, c.a.d, nadat het formulier in de weergave formulaire.jsp door de webclient is verzonden. Het enige doel ervan is de door de gebruiker ingevoerde waarden weer te geven. De code ervan is als volgt:

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

We introduceren hier twee nieuwe tagbibliotheken: struts-bean en struts-logic. De struts-bean-bibliotheek biedt toegang tot objecten die zich in de verzoek-, sessie- of applicatiecontext bevinden. Met de struts-logic-bibliotheek kun je uitvoeringslogica invoeren door middel van tags. Deze twee bibliotheken zijn geenszins onmisbaar. Zoals we hebben gezien, kan een pagina JSP:

  • objecten ophalen uit de request (request.getAttribute(...)), de sessie (session.getAttribute(...)) of de applicatiecontext
  • dynamische delen opnemen in de code HTML door middel van variabelen <%= variabele %>
  • Java-code bevatten <% Java-code %>

Het opnemen van Java-code in JSP-pagina’s stoort iedereen die een strikte scheiding wil tussen applicatielogica (Java-code) en presentatie (gebruik van tags). Daarom zijn er voor hen tagbibliotheken ontwikkeld.

We gaan te werk zoals bij de weergave formulaire.jsp en zullen elk van de tags in de code van confirmation.jsp toelichten, voor zover deze nog niet in de weergave formulaire.jsp aan bod zijn gekomen. Allereerst merken we op dat de pagina begint met het declareren van de drie tagbibliotheken die erin worden gebruikt:

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

Laten we er ook nog even aan herinneren dat deze drie bibliotheken moeten worden gedeclareerd in het bestand web.xml van de applicatie. We gaan nu de tags van het document formulaire.jsp toelichten:

balise
<bean:write name="dynaFormulaire" scope="session" property="opt"/>
fonction
schrijft een waarde naar de huidige HTML-stream. De tag bean:write ondersteunt de volgende attributen:
name: naam van het te gebruiken object
scope: bereik (request, session, context) waarin naar dit object moet worden gezocht
property: veld van het object dat met name wordt aangeduid en waarvan de eigenschap moet worden geschreven. Dit veld kan een object van elk type zijn. De methode toString van het object wordt gebruikt.
Hier wordt de waarde van het veld opt van dynaFormulaire geschreven. Dit is ofwel „ja” als de gebruiker het keuzerondje met het attribuut value="ja" heeft aangevinkt, ofwel „nee” als hij het keuzerondje met het attribuut value="nee" heeft aangevinkt
balise
<bean:write name="dynaFormulaire" scope="session" property="chk1"/>
fonction
schrijft de waarde van het veld chk1 van dynaFormulaire. Dit is ofwel "on" als de gebruiker het selectievakje heeft aangevinkt, ofwel "off" in het tegenovergestelde geval. Hetzelfde geldt voor chk2 en chk3.
balise
<bean:write name="dynaFormulaire" scope="session" property="champSaisie"/>
fonction
schrijft de waarde van het veld champSaisie uit dynaFormulaire, dat wil zeggen de tekst die de gebruiker in dit veld heeft ingevoerd. Hetzelfde geldt voor mdp, boiteSaisie.
balise
<bean:write name="dynaFormulaire" scope="session" property="combo"/>
fonction
schrijft de waarde van het keuzemenu-veld van dynaFormulaire. Dit is de value-attribuut van het door de gebruiker geselecteerde <option>-element.
balise
<bean:write name="dynaFormulaire" scope="session" property="listeSimple"/>
fonction
schrijft de waarde van het veld listeSimple over van dynaFormulaire. Dit is de waarde van het door de gebruiker geselecteerde <option>-element, indien er een is geselecteerd. Anders is de tekenreeks leeg.
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
Hier introduceren we logische tags. We hebben te maken met een keuzelijst. De waarde van het veld listeMultiple van het object dynaFormulaire is een array van strings. In Java zouden we een lus schrijven. Met de tag `logic:iterate` kunnen we dezelfde lus uitvoeren zonder Java-code te schrijven. De tag `logic:iterate` heeft in het voorbeeld de volgende attributen:
name="dynaFormulaire": naam van het te gebruiken object
property="listeMultiple": naam van de eigenschap die in het door name aangegeven object de verzameling bevat die in de lus wordt doorlopen. Hier is deze verzameling de array met de geselecteerde waarden in listeMultiple. Deze array kan leeg zijn.
id="choix": identificatie die bij elke lusronde het huidige element van de array aanduidt. Tijdens de eerste iteratie staat ‘choix’ voor listeMultiple[0], tijdens de tweede voor listeMultiple[1], enzovoort.
indexID="index": identificatie die de index van het huidige element in de array aangeeft bij elke lusronde. Bij de eerste iteratie heeft `index` de waarde 0, bij de tweede de waarde 1, enzovoort.
De code HTML tussen de tags <logic:iterate ...> en </logic:iterate> wordt herhaald voor elk element van de verzameling die wordt aangeduid door het paar (name,property). Het dynamische deel van deze code is als volgt:
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
Uit het voorgaande volgt dat bij iteratie nr. i (i>=0) de gegenereerde code HTML gelijk is aan de volgende code:
          <td>liste multiple[<%=i%>]</td>
          <td><%=listeMultiple[i]%></td>
balise
    <html:link page="/affiche.do">
            Retour au formulaire
        </html:link>    
fonction
genereert een link die is afgestemd op de context van de applicatie, waardoor het niet nodig is om deze te kennen. De code HTML die door deze tag wordt gegenereerd, is als volgt:
<a href="/formulaire2/affiche.do">Retour au formulaire</a>

6.5. De Java-klassen

Het configuratiebestand struts-config.xml verwijst naar twee Java-klassen:

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

De klasse DynaFormulaire is de klasse die de waarden van weergave nr. 1 formulaire.jsp zal bevatten. De klasse InitFormulaireAction is de klasse die de waarden verwerkt van het formulier dat via de knop [Envoyer] van formulaire.jsp is verzonden.

6.5.1. De klasse DynaFormulaire

Om de waarden van een formulier op te slaan, volstaat een object van het type DynaActionForm, tenzij een van de methoden reset of validate van deze klasse opnieuw moet worden gedefinieerd. In dit geval hoeft de methode validate niet opnieuw te worden gedefinieerd, aangezien er geen gegevensvalidatie plaatsvindt. De methode reset moet echter wel opnieuw worden gedefinieerd. De velden van het object **DynaFormulaire** krijgen namelijk hun waarden uit het formulier dat door de webclient is verzonden. Sommige velden ontvangen echter mogelijk geen waarde als ze niet in het verzoek voorkomen. Dit gebeurt in de volgende gevallen:

  • een selectievakje dat niet door de gebruiker is aangevinkt
  • een lijst met meer dan 1 item of er is geen optie geselecteerd

Bij formulieren met dit type component moet de reset-methode

  • de waarde "off" toekennen aan het veld dat gekoppeld is aan het selectievakje
  • de lege tekenreeks toewijzen aan het veld dat gekoppeld is aan een lijst met één selectie
  • een array met nul elementen aan het veld toewijzen dat gekoppeld is aan een lijst met meerdere selecties

Als deze velden dus geen waarde uit de query ontvangen, behouden ze de waarde die door de reset is toegewezen; deze waarde komt overeen met de status van het onderdeel in het door de gebruiker gevalideerde formulier (selectievakje niet aangevinkt, lijst zonder geselecteerd item).

De code van de klasse DynaFormulaire, een afgeleide klasse van DynaActionForm, is als volgt:

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){
    // selectievakjes resetten – waarde ‘uit’
    set("chk1","off");
    set("chk2","off");
    set("chk2","off");
    // listeSimple resetten - lege tekenreeks
    set("listeSimple","");
     // listeMultiple resetten - lege tabel
    set("listeMultiple",new String[]{});
  }
}

6.5.2. De klasse InitFormulaireAction

De klasse InitFormulaireAction is in het bestand struts-config.xml gekoppeld aan de actie /init:

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

De actie /init wordt slechts één keer gebruikt bij de initiële aanmaak van het object DynaFormulaire. Het doel ervan is om inhoud te leveren aan de drie lijsten van het keuzemenu, listeSimple, listeMultiple. Deze inhoud wordt geleverd in de vorm van drie tabellen, die eigenschappen zijn van het object 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>            

Zodra de tabellen valeursCombo, valeursListeSimple en valeursListeMultiple door InitFormulaireAction zijn geïnitialiseerd, hoeven ze niet meer te worden geïnitialiseerd. Het object dynaFormulaire wordt namelijk in de sessie geplaatst en behoudt daardoor zijn waarde tijdens de verschillende vraag-antwoordcycli. Daarom wordt de actie /init slechts één keer uitgevoerd. De code van InitFormulaireAction is als volgt:

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 {

     // het formulier voorbereiden voor weergave

     // de benodigde informatie voor het formulier wordt in de bijbehorende bean geplaatst
    DynaFormulaire formulaire = (DynaFormulaire) form;
    formulaire.set("valeursCombo", getValeurs(5, "combo"));
    formulaire.set("valeursListeSimple", getValeurs(7, "simple"));
    formulaire.set("valeursListeMultiple", getValeurs(10, "multiple"));
     // de controle wordt teruggegeven
    return mapping.findForward("afficherFormulaire");
  } //wordt uitgevoerd

   // lijst met waarden van de keuzelijst
  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;
  }
}
  • De klasse is afgeleid van de klasse Action. Dit is verplicht.
  • De Struts-controller gebruikt een Action-object via de methode `execute`. Deze methode moet dus opnieuw worden gedefinieerd. Deze methode ontvangt de volgende parameters:
    • ActionMapping mapping: een object dat de configuratie van de applicatie vertegenwoordigt in struts-config.xml
    • ActionForm form: het formulier dat aan de actie is gekoppeld, indien er een is gedefinieerd in de configuratie van de actie (attribuut name van de actie).
    • HttpServletRequest request: het verzoek van de client
    • HttpServletResponse: het antwoord aan de client
  • de klasse InitFormulaireAction moet het formulier dynaFormulaire initialiseren. Dit formulier wordt aan de methode `execute` doorgegeven als de parameter ActionForm form. Ter herinnering: dynaFormulaire is van het type DynaFormulaire, een klasse die is afgeleid van de klasse DynaActionForm, die op haar beurt is afgeleid van de klasse ActionForm.
  • In de methode `execute` worden waarden toegewezen aan de drie velden valeursCombo, valeursListeSimple en valeursListeMultiple met behulp van de methode `set` van de klasse DynaActionForm. Deze waarden zijn willekeurige arrays, ter wille van de eenvoud. Merk op dat de methode `set` een waarde toekent aan een bestaand veld. Deze methode kan niet worden gebruikt om nieuwe velden aan te maken. Daarom is het noodzakelijk om de drie velden valeursCombo, valeursListeSimple, valeursListeMultiple te definiëren in de definitie van het object dynaFormulaire in struts-config.xml.
  • De methode `execute` wordt afgesloten door de sleutel van de weer te geven weergave terug te sturen naar de controller als antwoord aan de client. In dit geval is dat de sleutel afficherFormulaire, die in het bestand struts-config.xml is gekoppeld aan de weergave /vues/formulaire.jsp.

6.6. Implementatie

De structuur van de applicatie is als volgt:

  

Image

Image

Ter herinnering: het bovenstaande bestand ApplicationResources.properties is nodig voor de struts-bean-tagbibliotheek. We weten dat dit bestand de berichten van de applicatie bevat. Deze zijn toegankelijk voor de struts-bean-bibliotheek. In dit geval definieert onze applicatie geen berichten. Het bestand ApplicationResources.properties bestaat wel, maar is leeg.

6.7. Conclusie

In deze les hebben we gedetailleerd beschreven hoe de verschillende componenten van een formulier HTML moeten worden beheerd. We kunnen nu complexe formulieren gebruiken in onze Struts-applicaties.