6. Formularze HTML
Do tej pory korzystaliśmy z jednego formularza zawierającego jedynie dwa pola wprowadzania danych. W niniejszym rozdziale zamierzamy stworzyć i przetworzyć formularz wykorzystujący typowe elementy graficzne (przyciski opcji, pola wyboru, pola wprowadzania danych, listy rozwijane, listy).
6.1. Widoki aplikacji
Aplikacja będzie miała tylko dwa widoki. Pierwszy z nich przedstawia pusty formularz:
QZXW2HTMLP000547ZQX 1 - formulaire

Ten pierwszy widok, o nazwie formulaire.jsp, pozwoli nam na zastosowanie różnych tagów z biblioteki struts-html. Użytkownik wypełnia formularz:

Przycisk [Envoyer] pozwala uzyskać potwierdzenie wprowadzonych wartości. Będzie to drugi widok:

Ten drugi widok pozwoli nam na wykorzystanie dwóch kolejnych bibliotek tagów: struts-bean i struts-logic. Link [Retour au formulaire] pozwala nam powrócić do formularza w stanie, w jakim został wypełniony. W ten sposób powracamy do pierwszego widoku.
6.2. Architektura aplikacji
![]() |
- Formularz (widok 1) będzie reprezentowany przez dynamiczny obiekt Struts o nazwie dynaFormulaire, którego typ wywodzi się od typu DynaActionForm. Zostanie on wyświetlony przez widok formulaire.jsp.
- Akcja Struts o nazwie InitFormulaireAction będzie miała na celu pozyskanie danych niezbędnych do wyświetlenia formularza
- wypełniony formularz zostanie przetworzony przez akcję ForwardAction, która polegać będzie na przekierowaniu żądania do drugiego widoku confirmation.jsp. Widok ten zajmie się wyświetleniem wartości z formularza.
6.3. Konfiguracja aplikacji
6.3.1. Plik server.xml
Kontekst aplikacji będzie nosił nazwę /formulaire2. W związku z tym dodamy następujący wiersz do pliku server.xml serwera Tomcat:
Po wykonaniu tej czynności ewentualnie uruchomimy ponownie serwer Tomcat, aby uwzględnił nowy kontekst. Możemy sprawdzić poprawność tego kontekstu, wywołując stronę URL http://localhost:8080/formulaire2:

6.3.2. Plik web.xml
Plik konfiguracyjny aplikacji web.xml będzie wyglądał następująco:
<?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>
W odniesieniu do plików konfiguracyjnych web.xml, z którymi mieliśmy już do czynienia, wprowadzamy kilka zmian:
- wprowadzamy dwie nowe biblioteki tagów: struts-bean i struts-logic. Będą one wykorzystywane w widoku confirmation.jsp. Z kolei widok formulaire.jsp będzie korzystał z biblioteki struts-html.
6.3.3. Plik struts-config.xml
Plik struts-config.xml będzie wyglądał następująco:
<?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>
Znajdują się tu trzy główne sekcje:
- deklarację formularzy w sekcji <form-beans>
- deklaracja akcji w sekcji <action-mappings>
- deklaracja pliku zasobów w sekcji <message-ressources>
6.3.4. Obiekty (beans) formularzy aplikacji
Obiekty używane do reprezentowania formularzy HTML w aplikacji to obiekty typu ActionForm lub pochodne (DynaActionForm, DynaValidatorForm, ...). Nazywane są one „beanami”, ponieważ ich konstrukcja jest zgodna z zasadami obiektów typu JavaBeans. W naszej aplikacji występuje tylko jeden obiekt formularza typu „bean”, o nazwie dynaFormulaire i będący pochodną typu DynaActionForm. Będzie on wykorzystywany w następujących sytuacjach:
- przechowywanie danych niezbędnych do wyświetlenia widoku nr 1
- pobieranie wartości z formularza w widoku nr 1 po jego zatwierdzeniu (submit) przez użytkownika
- przechowywanie danych niezbędnych do wyświetlenia widoku nr 2
Struktura bean dynaFormulaire jest ściśle powiązana z formularzem widoku nr 1. Przyjrzyjmy się mu:
![]() |
Nr | Typ HTML | Rola |
<input name="opt" type="radio" value="tak"> <input name="opt" type="radio" value="nie"> | grupa powiązanych ze sobą przycisków opcji (ta sama nazwa) | |
<input name="chk1" type="radio" value="on"> <input name="chk2" type="radio" value="włączone"> <input name="chk3" type="radio" value="on"> | grupy pól wyboru (nie mają tej samej nazwy) | |
<input type="text" name="champSaisie" > | pole wprowadzania danych | |
<input type="password" name="mdp" > | pole hasła | |
<textarea name="boiteSaisie">...</textarea> | pole wprowadzania tekstu wielowierszowego | |
<select name="combo" size="1">..</select> | listy rozwijanej | |
<select name="listeSimple" size="3">..</select> | lista z możliwością wyboru jednej pozycji | |
<select name="listeMultiple" size="3" multiple>..</select> | lista z możliwością wielokrotnego wyboru | |
<input type="button" value="Wyczyść" onclick='effacerListe("listeSimple")'> | przycisk umożliwiający odznaczenie wybranych elementów w listeSimple (7) | |
<input type="button" value="Usuń" onclick='effacerListe("listeMultiple")'> | przycisk umożliwiający odznaczenie wybranych elementów w listeMultiple (8) | |
<input type="submit" value="Wyślij"> | przycisk przesyłania formularza | |
<input type="hidden" name="secret" value="..."> | ukryte pole |
Rozróżnijmy kilka przypadków:
- obiekt dynaFormulaire służy do przechowywania wartości z powyższego formularza HTML, który zostanie wysłany za pomocą przycisku [Envoyer]. Musi on zatem zawierać te same pola, co formularz HTML. Typ pola jest określany zgodnie z następującą regułą:
- jeśli pole HTML zawiera tylko jedną wartość, wówczas pole w dynaFormulaire będzie typu java.lang.String
- jeśli pole HTML zawiera wiele wartości, wówczas pole w dynaFormulaire będzie miało typ java.lang.String[]
W powyższym formularzu HTML jedynie pole listeMultiple może być powiązane z wieloma wartościami (wybranymi przez użytkownika). Zatem pierwsza definicja obiektu dynaFormulaire wyglądałaby następująco:
<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>
W jaki sposób formularz dynaFormulaire zostanie wypełniony wartościami z formularza HTML przesłanego przez klienta internetowego?
Pole „opt” otrzyma wartość „tak”, jeśli zaznaczono pole HTML <input type="radio" name="opt" value="tak">, a wartość „nie”, jeśli zaznaczono pole <input type="radio" name="opt" value="nie">. | |
pole chk1 otrzyma wartość „włączone”, jeśli zaznaczono pole HTML <input name="chk1" type="radio" value="1">, w przeciwnym razie nie otrzyma żadnej wartości. W tym ostatnim przypadku pole chk1 zachowa swoją poprzednią wartość. | |
to samo | |
to samo | |
Pole champSaisie otrzyma tekst wprowadzony przez użytkownika w polu HTML <input type="text" name="champSaisie">. Tekst ten może ewentualnie stanowić pusty ciąg znaków. | |
Pole „mdp” otrzyma tekst wprowadzony przez użytkownika w polu HTML <input type="password" name="mdp">. Tekst ten może ewentualnie być pusty. | |
Pole boiteSaisie otrzyma tekst wprowadzony przez użytkownika w polu HTML <textarea name="boiteSaisie">...</textarea>. Tekst ten stanowi jeden ciąg znaków, złożony z wierszy wpisanych przez użytkownika, oddzielonych od siebie sekwencją znaków „\r\n”. Uzyskany tekst może ewentualnie być pustym ciągiem znaków. | |
pole kombi otrzyma opcję wybraną przez użytkownika w polu HTML <select name="combo" size="1">..</select>. Wybrana opcja to ta, która pojawia się w polu kombi. Jeśli wybrana opcja HTML jest typu <option value="XX">YY</option>, pole kombi otrzyma wartość „XX”. Jeśli wybrana opcja HTML jest typu <option>YY</option>, pole listy rozwijanej otrzyma wartość „YY”. | |
pole listeSimple otrzyma opcję wybraną przez użytkownika w polu HTML <select name="listeSimple" size="..">..</select>, o ile taka istnieje. Jeśli nie ma takiej opcji, pole listeSimple nie otrzyma żadnej wartości i zachowa swoją poprzednią wartość. Wartość faktycznie przypisana do pola listeSimple jest zgodna z zasadami określonymi dla listy rozwijanej. | |
pole listeMultiple typu String[] otrzyma opcje wybrane przez użytkownika w polu HTML <select name="listeMultiple" size=".." multiple>..</select>, jeśli takie istnieją. Jeśli nie ma żadnych opcji, tablica listeMultiple nie otrzyma żadnych wartości, a jej zawartość pozostanie niezmieniona. Wartości faktycznie przypisane do tablicy listeMultiple są zgodne z zasadami określonymi dla pola kombi. | |
pole „secret” otrzyma wartość XX z pola HTML <input type="hidden" name="secret" value="XX">. Tekst ten może ewentualnie stanowić pusty ciąg znaków. |
- Obiekt dynaFormulaire służy do nadania początkowej zawartości widoku nr 1. Wartości poprzednich pól zostaną wykorzystane w następujących celach:
musi mieć wartość „tak” lub „nie”, aby przeglądarka wiedziała, który przycisk opcji zaznaczyć | |
jeśli chk1 ma wartość „on”, pole wyboru zostanie zaznaczone, w przeciwnym razie nie zostanie zaznaczone | |
to samo | |
to samo | |
wartość pola zostanie wyświetlona w polu wprowadzania danych champSaisie | |
wartość pola zostanie wyświetlona w polu wprowadzania hasła | |
wartość pola zostanie wyświetlona w polu wprowadzania danych boiteSaisie | |
wartość tego pola określa, który element listy rozwijanej ma zostać zaznaczony po wyświetleniu formularza | |
to samo | |
wartości tabeli listeMultiple wskazują, które elementy listy wielokrotnego wyboru mają być zaznaczone podczas wyświetlania formularza | |
wartość pola zostanie przypisana do atrybutu „value” pola HTML secret. |
Widok nr 1 wymaga dodatkowych informacji:
- lista wartości do wyświetlenia w liście rozwijanej
- lista wartości do wyświetlenia w liście listeSimple
- lista wartości, które mają być wyświetlone na liście listeMultiple
Istnieje kilka sposobów przekazania tych informacji do widoku. Na przykład wystarczą tabele umieszczone w zapytaniu przekazywanym do widoku. W tym przypadku umieszczamy te tabele w 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>
Formularz dynaFormulaire zostanie zainicjowany przez akcję /init, która wywoła obiekt pochodny od klasy Action o nazwie InitFormulaireAction. To właśnie ten obiekt będzie odpowiedzialny za utworzenie trzech tablic niezbędnych do wyświetlenia trzech list oraz umieszczenie ich w bean'ie dynaFormulaire. Plik konfiguracyjny nadaje temu beanowi zakres równy sesji. Oznacza to, że kontroler Struts umieści ten bean w sesji. Dzięki temu nie będziemy musieli go odtwarzać między kolejnymi cyklami żądanie-odpowiedź. Akcja /init zostanie zatem wywołana tylko raz.
- Obiekt dynaFormulaire jest również wykorzystywany do dostarczania treści widoku nr 2. Widok ten ogranicza się do wyświetlania wartości tego obiektu.
6.3.5. Akcje aplikacji
Akcje są realizowane przez obiekty typu Action lub pochodne. Konfiguracja akcji odbywa się wewnątrz tagów <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>
Należy zauważyć, że nie zawsze z akcją powiązany jest formularz. Tak jest w przypadku powyższej akcji /affiche. Zanim omówimy szczegółowo każdą akcję, przypomnijmy sobie, jak działa para „akcja-formularz” powiązana w tagu <action>:
- akcja rozpoczyna się od żądania wysłanego przez klienta internetowego, a kończy się wysłaniem strony odpowiedzi. Jest to cykl żądanie-odpowiedź między klientem a serwerem internetowym. Żądanie jest odbierane przez kontroler Struts typu ActionServlet lub jego pochodną. To właśnie ten kontroler wysyła odpowiedź.
- Bean formularza typu ActionForm lub pochodnego jest tworzony, jeśli jeszcze nie istnieje. Kontroler sprawdza, czy może znaleźć obiekt o nazwie name w zakresie określonym przez scope. Jeśli tak, to go wykorzystuje. Jeśli nie, to tworzy go i umieszcza w zakresie określonym przez scope, powiązając go z atrybutem wskazanym przez name.
Na przykład w przypadku akcji /init kontroler wykona operację request.getSession().getAttribute("dynaFormulaire"), aby sprawdzić, czy obiekt dynaFormulaire został już utworzony. Jeśli nie, utworzy go i umieści w sesji za pomocą instrukcji typu request.getSession().setAttribute("dynaFormulaire", new DynaFormulaire(...)).
- Kontroler wyszuka również obiekt Action typu wskazanego przez atrybut type. Jeśli go nie znajdzie, utworzy go, w przeciwnym razie wykorzysta istniejący.
- Zostanie wywołana metoda reset fasoli formularza. Fasola ta, z wyjątkiem sytuacji podczas jej pierwotnego utworzenia, jest ponownie wykorzystywana. Zawiera wówczas dane, które może zaistnieć potrzeba „wyczyścić”. Czynność tę wykonuje się w metodzie reset fasoli ActionForm lub jej pochodnej.
- jeśli akcja jest celem formularza wysyłanego metodą POST, wówczas wartości z formularza zawarte w żądaniu klienta są kopiowane do pól o tej samej nazwie w beanie formularza. Należy zauważyć, że przed tym kopiowaniem wywołano metodę reset.
- Jeśli w konfiguracji określono atrybut `validate="true"`, wywołana zostanie metoda `validate` obiektu formularza. Metoda ta musi wówczas zweryfikować dane zawarte w obiekcie formularza. Weryfikacja ta ma miejsce najczęściej tylko wtedy, gdy formularz właśnie otrzymał nowe dane za pośrednictwem wysłanego formularza i chce się sprawdzić poprawność tych danych. Metoda ta zwraca kontrolerowi ewentualną listę błędów w obiekcie ActionErrors.
- Jeśli obiekt ActionErrors nie jest pusty, kontroler wyświetla widok określony przez atrybut input akcji.
- Jeśli walidacja danych nie jest wymagana lub przebiegła pomyślnie, kontroler uruchamia metodę `execute` obiektu typu `Action` lub jego pochodnej, powiązanego z bieżącą akcją. To właśnie w tej metodzie przetwarzane jest żądanie klienta internetowego. Metoda `execute` zwraca obiekt typu `ActionForward`, indeksowany za pomocą kluczy typu ciąg znaków. Klucze te są zadeklarowane przez tagi forward skonfigurowanej akcji. W naszym przykładzie akcja /init ma tylko jeden tag forward. Przypisuje on klucz „afficherFormulaire” do widoku formulaire.jsp.
- Kontroler wyświetla widok, z którym powiązany jest otrzymany klucz. Widok ten może w rzeczywistości być akcją, w którym to przypadku powyższy proces się powtarza.
Akcja /init
<action
path="/init"
name="dynaFormulaire"
validate="false"
scope="session"
type="istia.st.struts.formulaire.InitFormulaireAction"
>
<forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
</action>
- Akcja /init odbywa się zazwyczaj raz podczas pierwszego cyklu żądanie-odpowiedź, gdy użytkownik żąda obiektu URL http://localhost:8080/formulaire2/init.do
- obiekt dynaFormulaire jest tworzony lub ponownie wykorzystywany. Jest on pobierany (ponowne wykorzystanie) lub umieszczany (tworzenie) w sesji zgodnie z atrybutem scope.
- Wywoływana jest jego metoda reset. Co powinna ona wykonać? Zazwyczaj pola obiektu ActionForm są resetowane do wartości domyślnych. Jednak w tym przypadku nie zrobimy tego, ponieważ obiekt dynaFormulaire jest umieszczany w sesji (scope="session"). Pola obiektu dynaFormulaire muszą zatem zachować swoje wartości. Jakie są te wartości podczas początkowego utworzenia obiektu dynaFormulaire? Istnieją dwa przypadki:
- pole ma wartość początkową określoną w pliku konfiguracyjnym:
W tym przypadku kontroler Struts utworzy to pole z tą wartością początkową.
- pole nie ma wartości początkowej określonej w konfiguracji: zastosowanie mają reguły inicjalizacji języka Java. Zasadniczo pola liczbowe będą miały wartość zero, ciągi znaków będą miały wartość pustą, a pozostałe obiekty będą miały wartość null.
Przyjrzyjmy się początkowej konfiguracji 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>
Wartości początkowe pól w rekordzie dynaFormulaire po jego utworzeniu będą następujące:
Pole | Wartość początkowa |
„nie” | |
pusty ciąg znaków | |
pusty ciąg znaków | |
pusty ciąg znaków | |
pusty ciąg znaków | |
pusty ciąg znaków | |
pusty ciąg znaków | |
tablica pustych ciągów znaków | |
„xxx” | |
tablica pustych ciągów znaków |
- można by sobie wyobrazić, że metoda reset w dynaFormulaire nadaje wartości trzem tablicom, które mają zasilać trzy listy w widoku formulaire.jsp. Byłoby to tutaj możliwe, ponieważ dane w tych trzech tablicach są generowane w sposób arbitralny. Niemniej jednak najczęściej dane te pochodzą z modelu aplikacji, czyli z M w MVC. W tym przypadku, aby nie komplikować przykładu, przyjmiemy rozwiązanie pośrednie, polegające na wygenerowaniu tych wartości przez akcję InitFormulaireAction, a więc przez element C z MVC.
- Nie ma konieczności pisania metody reset w klasie dynaFormulaire, ponieważ klasa ActionForm, od której ona pochodzi, posiada taką metodę, która nic nie robi (brak inicjalizacji).
- Po wywołaniu metody reset klasy dynaFormulaire kontroler sprawdza atrybut validate akcji. W tym przypadku ma on wartość „false”. Metoda validate klasy dynaFormulaire nie zostanie wywołana.
- Obiekt InitFormulaireAction zostaje utworzony lub odnowiony, jeśli już istniał, a następnie wywoływana jest jego metoda `execute`. To właśnie ta metoda przypisze dowolne wartości do trzech tablic obiektu dynaFormulaire: valeursCombo, valeursListeSimple i valeursListeMultiple. Metoda zwraca obiekt ActionForward o kluczu „afficherFormulaire”.
- Kontroler wyświetla widok /vues/formulaire.jsp, który został powiązany z kluczem „afficherFormulaire” za pomocą znacznika forward akcji /init.
Akcja /confirmation
<action
path="/confirmation"
name="dynaFormulaire"
validate="false"
scope="session"
parameter="/vues/confirmation.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
- Akcja /confirmation ma miejsce, gdy użytkownik naciśnie przycisk [Envoyer] w widoku nr 1. Przeglądarka „wysyła” wówczas do kontrolera Struts formularz wypełniony przez użytkownika.
- Obiekt dynaFormulaire jest pobierany z sesji
- wywoływana jest jego metoda reset. Po jej wywołaniu kontroler Struts skopiuje wartości pól formularza przesłanego przez klienta do pól o tej samej nazwie w obiekcie dynaFormulaire. Przyjrzyjmy się ponownie liście pól tego obiektu i zobaczmy, jak przebiega to kopiowanie:
Pole | Powiązany kod HTML | Wartość pola po skopiowaniu wartości z formularza |
<input type="radio" name="opt" value="tak">Tak <input type="radio" name="opt" value="nie" checked="checked">Nie | – „tak” lub „nie” w zależności od zaznaczonego przycisku opcji | |
<input type="checkbox" name="chk1" value="on"> | - „on”, jeśli pole wyboru chk1 zostało zaznaczone - zachowuje poprzednią wartość, jeśli pole wyboru chk1 nie zostało zaznaczone | |
<input type="checkbox" name="chk2" value="on"> | - „on”, jeśli pole wyboru chk2 zostało zaznaczone - zachowuje poprzednią wartość, jeśli pole wyboru chk2 nie zostało zaznaczone | |
<input type="checkbox" name="chk2" value="on"> | - „on”, jeśli pole wyboru chk3 zostało zaznaczone - zachowuje poprzednią wartość, jeśli pole wyboru chk3 nie zostało zaznaczone | |
<input type="text" name="champSaisie" value=""> | - wartość wpisana przez użytkownika w polu champSaisie | |
<input type="password" name="mdp" value=""> | - wartość wprowadzona przez użytkownika w polu „mdp” | |
<textarea name="boiteSaisie"></textarea> | - wartość wprowadzona przez użytkownika w polu boiteSaisie | |
<select name="combo">...</select> | - wartość wybrana przez użytkownika w combo | |
<select name="listeSimple" size="3">...</select> | - wartość wybrana przez użytkownika w polu listeSimple | |
<select name="listeMultiple" multiple="multiple" size="5"> | - tablica ciągów znaków zawierająca wartości wybrane przez użytkownika w listeMultiple | |
<input type="hidden" name="secret" value="xxx"> | - „xxx”. |
Mamy problem z polami, które niekoniecznie otrzymują wartość w żądaniu wysyłanym przez przeglądarkę. Dotyczy to pól wyboru od chk1 do chk3 oraz dwóch list: listeSimple i listeMultiple. W takim przypadku pola te zachowują swoją poprzednią wartość, czyli tę uzyskaną podczas poprzedniego cyklu żądania-odpowiedzi.
Rozważmy na przykład pole wyboru chk1 i załóżmy, że w poprzednim cyklu żądania-odpowiedzi użytkownik zaznaczył to pole. Przeglądarka wysłała wówczas w łańcuchu parametrów swojego żądania informację chk1="on". Twórca strony przypisał zatem wartość „on” do pola chk1 w dynaFormulaire. Załóżmy teraz, że w bieżącym cyklu użytkownik nie zaznacza pola wyboru chk1. W takim przypadku w łańcuchu parametrów nowego żądania przeglądarka nie wysyła czegoś w rodzaju chk1="off", lecz nie wysyła nic. W rezultacie pole chk1 w dynaFormulaire zachowa wartość „on”, a zatem będzie miało wartość, która nie odzwierciedla wartości z formularza zatwierdzonego przez użytkownika. Aby rozwiązać ten problem, wykorzystamy metodę reset w dynaFormulaire. W tej metodzie ustawimy trzy pola chk1, chk2, chk3 na „off”. W naszym przykładzie dotyczącym chk1, jeśli użytkownik:
- zaznaczy pole wyboru chk1. Wówczas przeglądarka wyśle informację chk1="on", a pole chk1 w dynaFormulaire zmieni się na „on”
- nie zaznaczy pola wyboru chk1. Wówczas przeglądarka nie wyśle wartości dla pola chk1, które zachowa swoją poprzednią wartość „off”. W obu przypadkach wartość zapisana w polu chk1 w dynaFormulaire jest poprawna.
Problem ten dotyczy obu list: listeSimple i listeMultiple. Jeśli na tych listach nie wybrano żadnej opcji, nie pojawią się one w parametrach zapytania i w związku z tym zachowają swoje poprzednie wartości. W metodzie reset dynaFormulaire zresetujemy listeSimple za pomocą pustego ciągu znaków, a listeMultiple za pomocą tablicy ciągów o długości 0.
- Po wywołaniu metody reset obiektu dynaFormulaire kontroler kopiuje do pól obiektu dynaFormulaire informacje, które zostały mu przesłane w żądaniu klienta
- tworzony lub ponownie wykorzystywany jest obiekt ForwardAction, a następnie wywoływana jest jego metoda `execute`. ForwardAction jest predefiniowaną klasą, która zwraca obiekt ActionForward wskazujący na widok zdefiniowany przez atrybut „parameter” akcji, w tym przypadku /vues/confirmation.jsp.
- Kontroler wysyła ten widok. Cykl zostaje zakończony.
Akcja /wyświetla
<action
path="/affiche"
parameter="/vues/formulaire.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
- Akcja /affiche jest uruchamiana poprzez kliknięcie linku [Retour vers le formulaire] w widoku nr 2.
- W tym przypadku nie ma formularza powiązanego z tą akcją. Przechodzimy więc od razu do wykonania metody `execute` obiektu `ForwardAction`, która zwróci obiekt `ActionForward` wskazujący na widok `/vues/formulaire.jsp`.
6.3.6. Plik komunikatów aplikacji
Trzecia sekcja pliku struts-config.xml to sekcja zawierająca komunikaty:
Plik ApplicationResources.properties znajduje się w katalogu WEB-INF/classes. Będzie on pusty. Nawet jeśli jest pusty, musi zostać zadeklarowany w pliku konfiguracyjnym, w przeciwnym razie biblioteka tagów struts-bean, którą omówimy nieco później, wygeneruje błąd. Biblioteka ta jest wykorzystywana przez widok confirmation.jsp.
6.4. Kod widoków
6.4.1. Widok formulaire.jsp
Przypomnijmy, że ten widok jest wyświetlany w dwóch przypadkach:
- przy wywołaniu akcji /init podczas pierwszego cyklu żądanie-odpowiedź
- przy wywołaniu akcji /affiche w kolejnych cyklach
Kod widoku formulaire.jsp wygląda następująco:
<%@ 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>
Ta strona JSP wykorzystuje tagi pochodzące z biblioteki struts-html. Należy pamiętać, że aby korzystać z biblioteki tagów, należy:
- zadeklarować ją w pliku web.xml aplikacji za pomocą tagu <tag-lib>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
- umieścić kod tej biblioteki w dowolnym miejscu w drzewie katalogów aplikacji, w tym przypadku WEB-INF/struts-html.tld
- zadeklarować użycie tej biblioteki na początku stron JSP, które z niej korzystają:
Widok formulaire.jsp wykorzystuje tagi, które teraz wyjaśnimy:
<body background="<html:rewrite page="/images/standard.jpg"/>"> | |||
tag html:rewrite pozwala pominąć nazwę aplikacji w plikach URL. Posiada on jeden atrybut:
Tak więc, jak widać powyżej, jeśli zdecydujemy się nazwać aplikację „formularz3”, kod atrybutu background nie musi być przepisywany. Tag html:rewrite wygeneruje nowy kod HTML background="/formulaire3/images/standard.jpg" |
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire"> | |||||||
Tag html:form pozwala wygenerować formularz o nazwie HTML. Posiada on kilka atrybutów:
Widać, że domyślnie wygenerowany kod HTML wykorzystuje metodę POST. W tym samym kodzie HTML nazwa akcji URL została przepisana tak, aby na początku znajdowała się nazwa aplikacji, a na końcu rozszerzenie .do. |
<html:radio name="dynaFormulaire" property="opt" value="tak">Tak</html:radio> | |||||||
tag html:radio służy do generowania tagu HTML <input type="radio" ...>. Obsługuje on różne atrybuty:
Tekst między tagiem początkowym a końcowym to tekst, który zostanie wyświetlony obok przycisku opcji. |
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox> | |||||||
tag html:checkbox służy do wygenerowania tagu HTML <input type="checkbox" ...>. Obsługuje on różne atrybuty:
Tekst między tagiem początkowym a końcowym to tekst, który zostanie wyświetlony obok pola wyboru. |
<html:text name="dynaFormulaire" property="champSaisie" /> | |||||||
tag html:text służy do generowania tagu HTML <input type="text" ...>. Obsługuje on różne atrybuty:
|
<html:password name="dynaFormulaire" property="mdp" /> | |
tag html:password służy do generowania tagu HTML <input type="password" ...>. Obsługuje on różne atrybuty: |
<html:textarea name="dynaFormulaire" property="boiteSaisie" /> | |||||||
Tag html:textarea służy do wygenerowania tagu HTML <textarea>...</textarea>. Obsługuje on różne atrybuty:
|
<html:select name="dynaFormulaire" property="combo">....</html:select> | |||||||
Tag html:select służy do wygenerowania tagu HTML <select>...</select>. Obsługuje on różne atrybuty:
|
<html:select name="dynaFormulaire" property="combo"> <html:options name="dynaFormulaire" property="valeursCombo"/> </html:select> | |||||
Tag HTML:options służy do generowania tagów HTML <option>...</option> wewnątrz tagu HTML <select>. Istnieje wiele sposobów określenia, w jaki sposób znaleźć wartości wypełniające listę wyboru. W tym przypadku użyliśmy atrybutów name i property:
|
Dwie pozostałe listy są generowane analogicznie do poprzedniej:
<html:select name="dynaFormulaire" property="listeSimple" size="3">
<html:options name="dynaFormulaire" property="valeursListeSimple"/>
</html:select>
W powyższym przykładzie podano atrybut size o wartości innej niż 1, aby uzyskać listę zamiast pola kombi.
<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
<html:options name="dynaFormulaire" property="valeursListeMultiple"/>
</html:select>
Powyżej określono atrybut multiple="true", aby uzyskać listę z możliwością wielokrotnego wyboru.
<html:hidden name="dynaFormulaire" property="secret"/> | |||||
tag html:hidden służy do wygenerowania tagu HTML <input type="hidden" ...>.
|
Aby dobrze zrozumieć związek między widokiem formulaire.jsp a beanem dynaFormulaire, który reprezentuje go w pamięci, należy pamiętać, że bean dynaFormulaire służy zarówno do odczytu, jak i zapisu:
![]() |
Żądanie jest wysyłane, gdy użytkownik kliknie przycisk [Envoyer] w formularzu. Przeglądarka „wysyła” wówczas formularz HTML do akcji /confirmation. Wyjaśniliśmy już, co się wtedy dzieje, a w szczególności, że pola w dynaFormulaire otrzymają wartości z pól o tej samej nazwie w formularzu HTML.
Co się dzieje, gdy kontroler żąda wyświetlenia widoku formulaire.jsp w odpowiedzi na żądanie? Przyjrzyjmy się ponownie tagom jeden po drugim:
<body background="<html:rewrite page="/images/standard.jpg"/>"> | |
generuje kod HTML |
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire"> ... </html:form> | |
generuje kod HTML |
<html:radio name="dynaFormulaire" property="opt" value="tak">Tak</html:radio> <html:radio name="dynaFormulaire" property="opt" value="nie">Nie</html:radio> | |
Jeśli pole opt w dynaFormulaire ma wartość „tak”, wygeneruj kod HTML |
<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> | |
Jeśli pola chk1 i chk3 w dynaFormulaire mają wartość „on”, a pole chk2 ma wartość „off”, wygeneruj kod HTML |
<html:text name="dynaFormulaire" property="champSaisie" /> | |
jeśli pole champSaisie ma wartość „to jest test”, generuje kod HTML |
<html:password name="dynaFormulaire" property="mdp" /> | |
jeśli wartość pola mdp wynosi „azerty”, generuje kod HTML |
<html:password name="dynaFormulaire" property="mdp" /> | |
jeśli wartość pola mdp wynosi „azerty”, generuje kod HTML |
<html:password name="dynaFormulaire" property="mdp" /> | |
jeśli wartość pola mdp wynosi „azerty”, generuje kod HTML |
<html:select name="dynaFormulaire" property="combo"> <html:options name="dynaFormulaire" property="valeursCombo"/> </html:select> | |
jeśli wartość pola combo wynosi „combo2”, generuje kod HTML |
<html:select name="dynaFormulaire" property="listeSimple" size="3"> <html:options name="dynaFormulaire" property="valeursListeSimple"/> </html:select> | |
jeśli wartość pola listeSimple wynosi „simple1”, generuje kod HTML |
<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true"> <html:options name="dynaFormulaire" property="valeursListeMultiple"/> </html:select> | |
jeśli pole listeMultiple jest tablicą {"multiple0", "multiple2"}, generuje kod HTML |
<html:hidden name="dynaFormulaire" property="secret"/> | |
jeśli pole secret ma wartość „xxx”, generuje kod HTML |
<html:submit>Wyślij</html:submit> | |
generuje kod HTML |
Ostatnią rzeczą, którą należy wyjaśnić, jest kod JavaScript zawarty na stronie JSP i powiązany z dwoma przyciskami [Effacer], które odznaczają elementy zaznaczone na listach listeSimple i listeMultiple:
<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>
Tag
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
generuje następujący kod HTML:
Aby zrozumieć kod JavaScript powiązany z przyciskami [Effacer], przypomnijmy, w jaki sposób różne elementy dokumentu internetowego są oznaczane w kodzie JavaScript wykorzystującym ten dokument:
Dane | Znaczenie |
oznacza cały dokument internetowy | |
oznacza zbiór formularzy zdefiniowanych w dokumencie | |
oznacza formularz nr i w dokumencie | |
oznacza formularz <form> o atrybucie name równym „nomFormulaire” | |
oznacza formularz <form> z atrybutem name równym „nomFormulaire” | |
oznacza zbiór elementów należących do formularza określonego wyrażeniem [formulaire]. Zbiór ten obejmuje wszystkie tagi <input>, <textarea>, <select> z określonego formularza. | |
oznacza element nr i z [formulaire] | |
oznacza element z [formulaire], którego atrybut „name” ma wartość nomComposant | |
oznacza element [formulaire], którego atrybut name ma wartość nomComposant | |
oznacza wartość komponentu [composant] formularza [formulaire], gdy kod HTML tego formularza może posiadać atrybut value (<input>, <textarea>) | |
oznacza indeks opcji wybranej z listy. Służy zarówno do odczytu, jak i zapisu. Ustawienie tej właściwości na -1 powoduje odznaczenie wszystkich elementów listy. | |
oznacza tablicę opcji powiązanych z tagiem <select> | |
oznacza opcję nr i w wskazanym tagu <select> | |
wartość logiczna wskazująca, czy opcja nr i podanego tagu [select] jest zaznaczona (true), czy nie. Można ją wykorzystywać zarówno do odczytu, jak i zapisu |
Wróćmy do kodu JavaScript obu przycisków:
<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>
Po kliknięciu przycisku wykonywany jest kod powiązany z atrybutem „onclick”. W tym przypadku jest to kod wbudowany. Najczęściej zapisuje się to w postaci onclick="funkcja(...)", gdzie funkcja jest funkcją zdefiniowaną w tagu <script language="javascript">...</script>. Co robi powyższy kod? Omówmy kod pierwszego przycisku:
oznacza dokument internetowy, w którym znajduje się przycisk | |
oznacza formularz, w którym znajduje się przycisk | |
oznacza komponent listeSimple formularza | |
oznacza indeks wybranej opcji w listeSimple. Ustawienie tej właściwości na -1 powoduje odznaczenie wszystkich opcji. |
6.4.2. Widok confirmation.jsp
Przypomnijmy, że ten widok jest wyświetlany po zakończeniu akcji /potwierdzenia, c.a.d, po tym, jak formularz zawarty w widoku formulaire.jsp został przesłany przez klienta internetowego. Jego jedynym celem jest wyświetlenie wartości wprowadzonych przez użytkownika. Jego kod jest następujący:
<%@ 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>
W tym miejscu wprowadzamy dwie nowe biblioteki tagów: struts-bean i struts-logic. Biblioteka struts-bean umożliwia dostęp do obiektów umieszczonych w żądaniu, sesji lub kontekście aplikacji. Biblioteka struts-logic umożliwia wprowadzanie logiki wykonawczej za pomocą tagów. Obie te biblioteki nie są w żadnym wypadku niezbędne. Jak widzieliśmy, strona JSP może:
- pobierać obiekty z żądania (request.getAttribute(...)), sesji (session.getAttribute(...)) lub kontekstu aplikacji
- zawierać dynamiczne fragmenty w kodzie HTML za pomocą zmiennych <%= zmienna %>
- zawierać kod Java <% kod Java %>
Włączenie kodu Java do stron JSP przeszkadza wszystkim, którzy pragną ścisłego rozdzielenia logiki aplikacji (kodu Java) od prezentacji (użycia znaczników). Dlatego właśnie stworzono dla nich biblioteki znaczników.
Postąpimy tak samo jak w przypadku widoku formulaire.jsp i wyjaśnimy każdy z tagów obecnych w kodzie confirmation.jsp, o ile nie pojawiły się one już wcześniej w widoku formulaire.jsp. Na początek zauważmy, że strona rozpoczyna się od zadeklarowania trzech bibliotek znaczników, z których będzie korzystać:
<%@ 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" %>
Przypomnijmy również, że te trzy biblioteki muszą być zadeklarowane w pliku web.xml aplikacji. Teraz skomentujemy znaczniki w dokumencie formulaire.jsp:
zapisuje wartość w bieżącym strumieniu HTML. Tag bean:write akceptuje następujące atrybuty: name: nazwa obiektu, który ma zostać użyty scope: zakres (request, session, context), w którym należy szukać tego obiektu property: pole obiektu oznaczonego przez name, którego właściwość ma zostać zapisana. Pole to może być obiektem dowolnego typu. Zastosowana zostanie metoda toString tego obiektu. W tym przypadku zapisywana jest wartość pola opt obiektu dynaFormulaire. Wynikiem będzie „tak”, jeśli użytkownik zaznaczył przycisk opcji o atrybucie value="tak", lub „nie”, jeśli zaznaczył przycisk opcji o atrybucie value="nie" |
zapisuje wartość pola chk1 z dynaFormulaire. Wynikiem będzie „on”, jeśli użytkownik zaznaczył pole wyboru, lub „off” w przeciwnym razie. To samo dotyczy pól chk2 i chk3. |
zapisuje wartość pola champSaisie z pola dynaFormulaire, czyli tekst wpisany przez użytkownika w tym polu. To samo dotyczy pola mdp, boiteSaisie. |
zapisuje wartość pola rozwijanego dynaFormulaire. Otrzymamy atrybut „value” elementu <option> wybranego przez użytkownika. |
zapisuje wartość pola listeSimple z dynaFormulaire. Otrzymamy atrybut „value” elementu <option> wybranego przez użytkownika, jeśli taki istniał. W przeciwnym razie otrzymamy pusty ciąg znaków. |
W tym miejscu wprowadzamy znaczniki logiczne. Mamy do czynienia z listą wielokrotnego wyboru. Wartość pola listeMultiple obiektu dynaFormulaire jest tablicą typu String. W języku Java napisalibyśmy pętlę. Znacznik logic:iterate pozwala nam wykonać tę samą pętlę bez pisania kodu w Javie. W tym przykładzie znacznik logic:iterate ma następujące atrybuty: name="dynaFormulaire": nazwa obiektu, który ma zostać użyty property="listeMultiple": nazwa właściwości, która w obiekcie wskazanym przez atrybut name zawiera kolekcję, która będzie przeglądana w pętli. W tym przypadku kolekcją tą jest tablica wartości wybranych w obiekcie listeMultiple. Tablica ta może być pusta. id="choix": identyfikator wskazujący bieżący element tablicy w każdej iteracji pętli. Podczas pierwszej iteracji „choix” będzie reprezentować listeMultiple[0], podczas drugiej – listeMultiple[1] i tak dalej. indexID="index": identyfikator wskazujący indeks bieżącego elementu tablicy w każdej iteracji pętli. W pierwszej iteracji index będzie miał wartość 0, w drugiej – 1 i tak dalej. Kod HTML zawarty między tagami <logic:iterate ...> i </logic:iterate> jest powtarzany dla każdego elementu kolekcji wskazanej przez parę (name,property). Dynamiczna część tego kodu wygląda następująco:
Z powyższego wynika, że w iteracji nr i (i>=0) wygenerowany kod HTML jest równoważny następującemu kodowi: |
generuje link powiązany z kontekstem aplikacji, dzięki czemu nie trzeba go znać. Kod HTML wygenerowany przez ten tag wygląda następująco: |
6.5. Klasy Java
Plik konfiguracyjny struts-config.xml odwołuje się do dwóch klas 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"
>
Klasa DynaFormulaire to klasa, która będzie zawierać wartości z widoku nr 1 formulaire.jsp. Klasa InitFormulaireAction jest klasą, która będzie przetwarzać wartości formularza przesłanego za pomocą przycisku [Envoyer] z formulaire.jsp.
6.5.1. Klasa DynaFormulaire
Aby przechowywać wartości formularza, wystarczy obiekt typu DynaActionForm, chyba że konieczne jest przedefiniowanie jednej z metod reset lub validate tej klasy. W tym przypadku metoda validate nie wymaga przedefiniowania, ponieważ nie przeprowadzamy żadnej walidacji danych. Należy jednak zdefiniować na nowo metodę reset. Pola obiektu DynaFormulaire otrzymają bowiem swoje wartości z formularza przesłanego przez klienta internetowego. Niektóre pola mogą jednak nie otrzymać wartości, jeśli nie występują w żądaniu. Dzieje się tak w następujących przypadkach:
- pole wyboru, które nie zostało zaznaczone przez użytkownika
- lista zawierająca więcej niż jedną pozycję lub nie wybrano żadnej opcji
W przypadku formularzy zawierających ten typ komponentu metoda reset musi
- przypisać wartość „off” do pola powiązanego z pola wyboru
- przypisać pusty ciąg znaków do pola powiązanego z listą z jednym wyborem
- przypisać tablicę o zerowej długości zawierającą ciągi znaków do pola powiązanego z listą wielokrotnego wyboru
W ten sposób, jeśli pola te nie otrzymają wartości z zapytania, zachowują wartość przypisaną przez metodę reset, która odpowiada stanowi komponentu w formularzu zatwierdzonym przez użytkownika (pole niezaznaczone, lista bez żadnego wybranego elementu).
Kod klasy DynaFormulaire, klasy pochodnej od DynaActionForm, jest następujący:
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){
// resetowanie pól wyboru – wartość „off”
set("chk1","off");
set("chk2","off");
set("chk2","off");
// reset listeSimple – pusty ciąg znaków
set("listeSimple","");
// resetowanie listeMultiple – pusta tablica
set("listeMultiple",new String[]{});
}
}
6.5.2. Klasa InitFormulaireAction
Klasa InitFormulaireAction jest w pliku struts-config.xml powiązana z akcją /init:
<action
path="/init"
name="dynaFormulaire"
validate="false"
scope="session"
type="istia.st.struts.formulaire.InitFormulaireAction"
>
<forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
</action>
Akcja /init jest wykorzystywana tylko raz podczas początkowego tworzenia obiektu DynaFormulaire. Jej celem jest dostarczenie treści do trzech list w formularzu rozwijanym: listeSimple, listeMultiple. Treść ta jest dostarczana w postaci trzech tablic, będących właściwościami obiektu 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>
Gdy tabele valeursCombo, valeursListeSimple, valeursListeMultiple zostaną zainicjowane przez InitFormulaireAction, nie będzie już konieczne ich ponowne inicjowanie. Obiekt dynaFormulaire jest bowiem umieszczany w sesji i dzięki temu zachowuje swoją wartość w kolejnych cyklach żądanie-odpowiedź. Dlatego akcja /init jest wykonywana tylko raz. Kod InitFormulaireAction wygląda następująco:
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 {
// przygotowuje formularz do wyświetlenia
// umieszczamy niezbędne informacje dotyczące formularza w jego bean
DynaFormulaire formulaire = (DynaFormulaire) form;
formulaire.set("valeursCombo", getValeurs(5, "combo"));
formulaire.set("valeursListeSimple", getValeurs(7, "simple"));
formulaire.set("valeursListeMultiple", getValeurs(10, "multiple"));
// zwracamy kontrolę
return mapping.findForward("afficherFormulaire");
} //wykonuje
// lista wartości z listy rozwijanej
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;
}
}
- Klasa ta dziedziczy po klasie Action. Jest to obowiązkowe.
- Kontroler Struts wykorzystuje obiekt Action za pośrednictwem metody execute. Należy więc zdefiniować właśnie tę metodę. Metoda ta przyjmuje następujące parametry:
- ActionMapping mapping: obiekt reprezentujący konfigurację aplikacji w struts-config.xml
- ActionForm form: formularz powiązany z akcją, o ile został zdefiniowany w konfiguracji akcji (atrybut name akcji).
- HttpServletRequest request: żądanie klienta
- HttpServletResponse: odpowiedź dla klienta
- klasa InitFormulaireAction musi zainicjować formularz dynaFormulaire. Formularz ten trafia do metody execute w postaci parametru ActionForm form. Przypomnijmy, że dynaFormulaire jest typu DynaFormulaire, klasy pochodnej od klasy DynaActionForm, która z kolei jest pochodną klasy ActionForm.
- W metodzie `execute` wartości są przypisywane do trzech pól: `valeursCombo`, `valeursListeSimple` i `valeursListeMultiple` za pomocą metody `set` klasy `DynaActionForm`. Wartości te są dowolnymi tablicami, co ma na celu uproszczenie. Należy zauważyć, że metoda set przypisuje wartość do istniejącego pola. Nie można jej używać do tworzenia nowych pól. Dlatego konieczne jest zdefiniowanie trzech pól valeursCombo, valeursListeSimple, valeursListeMultiple w definicji obiektu dynaFormulaire w struts-config.xml.
- Metoda `execute` kończy działanie, zwracając do kontrolera klucz widoku, który ma zostać wyświetlony jako odpowiedź dla klienta. W tym przypadku jest to klucz afficherFormulaire, który w pliku struts-config.xml został powiązany z widokiem /vues/formulaire.jsp.
6.6. Wdrożenie
Struktura drzewa aplikacji wygląda następująco:
![]() | ![]() |
![]() | ![]() |


Przypomnijmy, że powyższy plik ApplicationResources.properties jest niezbędny dla biblioteki tagów struts-bean. Wiadomo, że plik ten zawiera komunikaty aplikacji. Są one dostępne dla biblioteki struts-bean. W tym przypadku nasza aplikacja nie definiuje żadnych komunikatów. Plik ApplicationResources.properties istnieje, ale jest pusty.
6.7. Wnioski
W tej lekcji szczegółowo omówiliśmy sposób zarządzania różnymi komponentami formularza HTML. Teraz możemy wykorzystywać złożone formularze w naszych aplikacjach Struts.






