9. Beispiel 07 – Formular-Tags
Wir werden das folgende Formular erstellen und auswerten:


Wir werden das Konzept der Parametereingabe, das wir für ein Texteingabefeld kennengelernt haben, auf die anderen HTML-Elemente eines Formulars ausweiten.
9.1. Das NetBeans-Projekt
![]() |
- in [1], die Ansichten des Projekts [Formx.jsp]
- in [2], die Struts-Konfigurationsdatei und die internationalisierten Meldungen
- in [3], die Aktionen in [Formx.java] und eine weitere Struts-Konfigurationsdatei.
9.2. Struts-Konfiguration
Die Datei [struts.xml] lautet wie folgt:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.custom.i18n.resources" value="messages" />
<include file="example/example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Form</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
</struts>
- Zeile 9: bindet eine weitere Konfigurationsdatei [example.xml] ein. Diese konfiguriert die Aktionen.
- Zeilen 11–19: Das Paket default. Es definiert eine Umleitungsadresse für die URL „/“. Diese wird zur URL „/example/Form.action“ umgeleitet.
Die Datei [example.xml], die die Aktionen konfiguriert, lautet wie folgt:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.jsp</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.jsp</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.jsp</result>
</action>
</package>
</struts>
- Zeilen 7–17: Definieren die Aktionen /example/Form, /example/Form1, /example/Form2, wobei /example der Namespace (Zeile 7) und Formx die Aktionen sind.
- Zeilen 8–10: Die Ausführung der Aktion Form führt zur Anzeige der Ansicht /example/Form.jsp.
- Zeilen 11–13: Die Ausführung der Aktion Form1 führt zur Anzeige der Ansicht /example/Form1.jsp.
- Zeilen 14–16: Die Ausführung der Aktion Form2 führt zur Anzeige der Ansicht /example/Form2.jsp.
9.3. Die Nachrichtendateien
Wir werden nicht näher auf die Internationalisierung des Projekts eingehen. Diese haben wir bereits in Beispiel 01 behandelt. Wir geben den Inhalt der Datei [messages.properties] wieder, damit der Leser die folgenden Ansichten besser verstehen kann.
Form.francais=Fran\u00E7ais
Form.anglais=Anglais
Form.titre=Struts 2 - les tags de formulaire
Form.message=Struts 2 - les tags de formulaire
Form.langues=langues
Form.textfield=1-textfield
Form.password=2-password
Form.textarea=3-textarea
Form.select1=4-select (multiple=false, size=1)
Form.select1.header=<-- select1 -->
Form.select2=5-select (multiple=false, size=3)
Form.select3=6-select (multiple=true, size=3)
Form.radio=7-radio
Form.checkbox=8-checkbox
Form.checkboxlist=9-checkboxlist
Form.hidden=10-hidden
Form.submitText=Valider
Form.buttonRazText=Raz
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.textfield=1-textfield
Confirmation.password=2-password
Confirmation.textarea=3-textarea
Confirmation.select1=4-select (multiple=false, size=1)
Confirmation.select2=5-select (multiple=false, size=3)
Confirmation.select3=6-select (multiple=true, size=3)
Confirmation.radio=7-radio
Confirmation.checkbox=8-checkbox
Confirmation.checkboxlist=9-checkboxlist
Confirmation.hidden=10-hidden
9.4. Die Ansicht [Form.jsp] – Eingabebereich
Sie sieht wie folgt aus:

Sie sieht wie folgt aus:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="url" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{url}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="url" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{url}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="textfield" key="Form.textfield" />
<s:password name="password" key="Form.password"/>
<s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
<s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
<s:radio name="radio" list="radioValues" key="Form.radio"/>
<s:checkbox name="checkbox" key="Form.checkbox"/>
<s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="submitText"/>
</s:form>
<hr/>
...
</body>
</html>
- Das Formular beginnt in Zeile 26 und endet in Zeile 38. In Zeile 26 fehlt das Attribut action. Dieses Attribut gibt an, an welche Aktion die Daten des Formulars gesendet werden sollen. Fehlt das Attribut action, werden sie an die Aktion gesendet, die zur Anzeige der Ansicht geführt hat, in diesem Fall die Aktion [Form].
- Zeile 27: ein Eingabefeld. Das Attribut key gibt dessen Beschriftung an. Das Attribut name ist der Name des Parameters, der übermittelt wird. Die für dieses Feld übermittelte Zeichenfolge hat folgende Form:
textfield=eingegebener_Text
Der Name des Parameters entspricht einem Feld der Aktion [Form]. Der Wert des Eingabefelds texte_saisi wird hier in das Feld textfield der Aktion [Form] eingefügt. Umgekehrt gilt: Wenn die Ansicht [Form.jsp] infolge der Aktion [Form] angezeigt wird, entspricht der Wert des Eingabefelds dem Wert des Felds textfield der Aktion [Form]. Dieses Feld wird also sowohl zum Lesen als auch zum Schreiben verwendet. Die Klasse [Form] muss hierfür über die Methoden getTextField und setTextField verfügen.
Diese Überlegung gilt für alle nachfolgenden Eingabe-Tags. Wir werden sie nicht wiederholen.
- Zeile 28: Eingabe eines Passworts. Die an die Aktion [Form] übermittelte Zeichenfolge hat folgende Form:
password=eingegebenes_Passwort
In der Aktion [Form] muss ein Feld password mit den entsprechenden Get-/Set-Methoden vorhanden sein.
- Zeile 29: Eingabe eines mehrzeiligen Textes in ein Feld mit 5 Zeilen und 40 Spalten. Die an die Aktion [Form] übermittelte Zeichenfolge hat das Format
textarea=Eingabe
In der Aktion [Form] muss ein Feld textarea mit den entsprechenden Get-/Set-Methoden vorhanden sein.
- Zeile 30: Ein Dropdown-Menü (size=1) mit Einfachauswahl. Es kann nur ein Wert aus der Liste ausgewählt werden. Die an die Aktion [Form] übermittelte Zeichenfolge hat folgende Form:
select1=ausgewählter_Wert
In der Aktion [Form] muss ein Feld select1 mit den entsprechenden Get-/Set-Methoden vorhanden sein.
Das Attribut key ist die Bezeichnung der Liste. Das Attribut list definiert die Liste der Werte, die in das Kombinationsfeld eingefügt werden sollen. Hier wird die Methode getSelect1Values der Aktion [Form] aufgerufen, um das Kombinationsfeld zu füllen. Diese Methode kann eine Sammlung, ein Wörterbuch oder ein Array zurückgeben. In diesem Fall gibt sie ein Array von Zeichenfolgen „[chaine1, chaine2, ...]“ zurück, das den folgenden HTML-Code generiert:
<option value="chaine1">chaine1</option>
<option value="chaine2">chaine2</option>
...
Der Text zwischen den Tags <option>...</option> wird in der Combobox angezeigt. Das Attribut value gibt den Wert an, der gesendet werden soll, wenn die Option vom Benutzer ausgewählt wird. Hier sind das Attribut value und der in der Combobox angezeigte Text identisch. Meistens ist dies jedoch nicht der Fall. Wenn die zweite Option ausgewählt wird, wird die folgende Zeichenfolge an die Aktion [Form] übermittelt:
select1=Zeichenkette2
Das Feld [Form].select1 erhält dann den Wert chaine2. Umgekehrt gilt: Wenn dieses Feld zum Zeitpunkt der Anzeige des Formulars den Wert chaine3 hat, wird visuell das dritte Element
<option value="chaine3">chaine3</option>
in der Kombinationsliste als ausgewählt angezeigt.
Das Attribut headerValue legt den Text fest, der als erste Option der Combobox angezeigt werden soll, und headerKey den Wert, der gesendet werden soll, wenn diese Option vom Benutzer ausgewählt wird.
- Zeile 31: Auch hier wieder eine Liste mit 3 Elementen (size=3): Im Gegensatz zur vorherigen Liste, bei der nur ein Element sichtbar ist, sind hier 3 Elemente der Liste sichtbar. Der Auswahlmodus bleibt derselbe. Es kann nur ein Element ausgewählt werden.
- Zeile 32: Wieder eine Liste, diesmal jedoch mit Mehrfachauswahl (multiple=true). In diesem Fall hat der an die Aktion [Form] übermittelte Wert folgende Form:
select3=Zeichenkette2&select3=Zeichenkette5
, wenn die Optionen chaine2 und chaine5 ausgewählt wurden. Wenn mehrere Werte für denselben Parameter übermittelt werden, hier select3, muss die Aktion ein Feld mit dem Namen des Parameters enthalten und vom Typ tableau sein. So könnte beispielsweise die Aktion [Form] ein Feld der folgenden Art enthalten:
String[] select3;
sowie die dazugehörigen get-/set-Methoden. Das Array select3 erhält dann das Zeichenfolgen-Array [chaine2,chaine5]. Umgekehrt bestimmen bei der Anzeige der Ansicht [Form.jsp] die Werte des Feldes [Form].select3 die Optionen der Liste select3, die als ausgewählt angezeigt werden. Es handelt sich weiterhin um Lese-/Schreibzugriff.
- Zeile 33: eine Gruppe von Optionsfeldern. Die Bezeichnung der Gruppe wird durch das Attribut key bereitgestellt. Die Beschriftungen der einzelnen Schaltflächen werden durch das Attribut list vorgegeben. Der Wert dieses Attributs ist der Name einer Methode der Aktion [Form], die eine Sammlung, ein Wörterbuch oder ein Array zurückgeben muss. Hier gibt die Methode [Form].getRadioValues ein Array von Zeichenketten [chaine1,chaine2,...] zurück, das die folgenden HTML-Tags generiert:
<input type="radio" name="radio" ... value="chaine1"/>chaine1
<input type="radio" name="radio" ... value="chaine2"/>chaine2
...
Wenn das Optionsfeld „chaine2“ ausgewählt ist, lautet der übermittelte Wert
radio=chaine2
und dieser Wert wird in das Feld [Form].radio eingefügt.
- Zeile 34: Ein Kontrollkästchen. Wenn es aktiviert ist, wird die folgende Parameterzeichenfolge an die Aktion [Form] übermittelt
checkbox=true
Ist das Kontrollkästchen nicht aktiviert, wird keine Parameterzeichenfolge übermittelt. Struts 2 verfügt über einen internen Mechanismus, der dafür sorgt, dass alles so abläuft, als ob die Zeichenfolge
checkbox=false
gesendet worden wäre.
- Zeile 35: Eine Liste von Kontrollkästchen. Es können mehrere Kontrollkästchen markiert werden. Die Bezeichnung der Gruppe wird durch das Attribut key bereitgestellt. Die Bezeichnungen der einzelnen Kontrollkästchen werden durch das Attribut list bereitgestellt. Der Wert dieses Attributs ist der Name einer Methode der Aktion [Form], die eine Sammlung, ein Wörterbuch oder ein Array zurückgeben muss. Hier gibt die Methode [Form].getCheckboxlistValues ein Array von Zeichenketten [chaine1,chaine2,...] zurück, das die folgenden HTML-Tags generiert:
<input type="checkbox" name="checkboxlist" ... value="chaine1"/>chaine1
<input type="checkbox" name="checkboxlist" ... value="chaine2"/>chaine2
...
Wenn der Benutzer die Kontrollkästchen mit den Bezeichnungen chaine2 und chaine5 auswählt, wird die folgende Zeichenfolge an die Aktion [Form] gesendet:
checkboxlist=Zeichenfolge2&checkboxlist=Zeichenfolge5
Die Tabelle [chaine2, chaine5] wird dem Feld [Form].checkboxlist zugewiesen, das daher wie bei Mehrfachauswahllisten vom Typ „Zeichenfolgen-Array“ sein muss. Umgekehrt bestimmen bei der Anzeige der Ansicht [Form.jsp] die Werte des Feldes [Form].checkboxlist, welche Kontrollkästchen angekreuzt werden.
- Zeile 36: ein verstecktes Feld. Ein verstecktes Feld ist ein Feld, das gesendet wird, ohne dass der Benutzer etwas eingibt. Sein Wert wird vom Programmierer festgelegt. Hier übernimmt das versteckte Feld seinen Wert aus dem Feld [Form].hidden. Derselbe Wert wird in folgender Form gesendet:
hidden=irgendetwas
und dem Feld „[Form].hidden“ wieder zugewiesen.
- Zeile 37: Eine Schaltfläche vom Typ submit. Ein Klick auf diese Schaltfläche übermittelt alle Werte des Formulars an die Aktion [Form]. Die Zeichenfolge der übermittelten Parameter sieht wie folgt aus:
textfield=Text&password=&textarea=Zeile1%0D%0AZeile2%0D%0A&select1=Null&select2=drei&select3=Null&select3=zwei&__multiselect_select3=&radio=blau&checkbox=true&__checkbox_checkbox=true&checkboxlist=Fahrrad&checkboxlist=Bus&__multiselect_checkboxlist=&hidden=initial&submitText=Bestätigen
9.5. Die Aktion [Form] – Eingabeteil
Der Code lautet wie folgt:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form extends ActionSupport {
// Konstruktor ohne Parameter
public Form() {
}
// Formularfelder
private String textfield = "texte";
private String password = "secret";
private String textarea = "ligne1\nligne2\n";
private String select1 = "zéro";
private String[] select1Values = new String[]{"zéro", "un", "deux"};
private String select2 = "trois";
private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String radio = "bleu";
private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
private Boolean checkbox = false;
private String[] checkboxlist = new String[]{"vélo", "bus"};
private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
private String hidden = "initial";
private String submitText;
// ausgewählte Werte im Feld „select3“
public String getSelect3SelectedValues() {
return getValue(select3);
}
// ausgewählte Werte im Checkbox-Listenfeld
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// Hilfsmethode
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// Getter und Setter der Felder
....
}
- Zeile 1: Das Feld, das dem Tag textfield des Formulars zugeordnet ist. Dient sowohl zur Initialisierung dieses Eingabefelds als auch zum Abrufen seines Werts. Erhält zum Zeitpunkt von POST den in diesem Feld eingegebenen Wert.
- Zeile 2: Das Feld, das dem Tag password des Formulars zugeordnet ist. Erhält zum Zeitpunkt des POST den in diesem Feld eingegebenen Wert.
- Zeile 13: Zugeordnet zum Tag textarea des Formulars. Erhält zum Zeitpunkt von POST den in diesem Feld eingegebenen Text.
- Zeile 14: zugeordnet dem Tag select1 des Formulars, eine Auswahlliste mit einer einzigen Auswahlmöglichkeit. Sein Anfangswert wählt ein Element aus der Kombinationsliste aus. Es wird das Element ausgewählt, dessen Attribut value diesem Wert entspricht. Zum Zeitpunkt von POST erhält das Attribut value den Wert der im Kombinationsfeld ausgewählten Option.
- Zeile 15: Die Zeichenfolgen, die in das Kombinationsfeld select1 eingegeben werden.
- Zeilen 16 und 17: wie select1
- Zeile 18: Mit dem Tag select1 des Formulars verknüpft ist eine Auswahlliste. Die Anfangswerte im Array wählen die entsprechenden Elemente der Liste aus. Es werden diejenigen Elemente ausgewählt, deren Attribut value einem dieser Elemente entspricht. Zum Zeitpunkt der Ausführung von POST werden die Attribute value der verschiedenen in der Kombinationsliste ausgewählten Optionen übernommen.
- Zeile 19: Die Zeichenfolgen, die in die Liste select3 übernommen werden
- Zeile 20: ist mit dem Tag radio des Formulars verknüpft. Sein Wert dient dazu, eines der Optionsfelder zu aktivieren, nämlich dasjenige, dessen Attribut value diesem Wert entspricht. Erhält zum Zeitpunkt von POST den Wert des markierten Optionsfelds.
- Zeile 21: Die verschiedenen Bezeichnungen und Werte der Optionsfelder.
- Zeile 22: Ist mit dem Tag checkbox des Formulars verknüpft. Sein Anfangswert dient dazu, das Kontrollkästchen zu aktivieren bzw. zu deaktivieren. Erhält zum Zeitpunkt von POST den Wert true, wenn das Kontrollkästchen markiert wurde, andernfalls den Wert false.
- Zeile 23: ist mit dem Tag checkboxlist des Formulars verknüpft. Die Anfangswerte in der Tabelle legen fest, welche Kontrollkästchen markiert werden. Es werden diejenigen Kontrollkästchen markiert, deren Attribut value einem dieser Anfangswerte entspricht. Zum Zeitpunkt der Ausführung von POST erhält die Funktion die Attribute value der verschiedenen markierten Kontrollkästchen.
- Zeile 24: Die Zeichenfolgen, die als Bezeichnungen für die Kontrollkästchen von checkboxlist verwendet werden.
- Zeile 25: Zugeordnet zum versteckten Feld hidden. Sein Anfangswert legt den Wert des versteckten Feldes fest. Bei der Ausführung von POST erhält es denselben Wert, da der Benutzer keine Möglichkeit hat, ihn zu ändern.
- Zeile 26: zugeordnet zum Tag submit. Bei der Ausführung von POST erhält es die Beschriftung der Schaltfläche. Auf dieses Feld kann verzichtet werden.
- Die Methoden in den Zeilen 29, 34 und 39 werden weiter unten erläutert.
9.6. Die Ansicht [Form.jsp] – Abschnitt „Bestätigung“
Die Ansicht [Form.jsp] enthält einen Abschnitt „Bestätigung der Eingaben“, der bisher noch nicht behandelt wurde:

Der Code lautet wie folgt:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
...
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="hidden"/>
</tr>
</table>
</body>
</html>
- Zeile 13: Zeigt den Wert des Felds [Form].textfield an
- Zeile 17: Zeigt den Wert des Felds [Form].password an
- Zeile 21: Zeigt den Wert des Felds [Form].textarea an
- Zeile 25: Zeigt den Wert des Felds [Form].select1 an
- Zeile 29: Zeigt den Wert des Felds [Form].select2 an
- Zeile 33: Zeigt die Werte der Tabelle [Form].select3 an. Verwende dazu die Methode [Form].getSelect3SelectedValues.
- Zeile 37: Zeigt den Wert des Felds [Form].radio an
- Zeile 41: Zeigt den Wert des Felds [Form].checkbox an
- Zeile 45: Zeigt die Werte des Arrays [Form].checkboxlist an. Verwenden Sie dazu die Methode [Form].getCheckboxlistSelectedValues.
- Zeile 49: Zeigt den Wert des Felds [Form].hidden an
9.7. Die Aktion [Form] – Bestätigungsteil
Die zuvor genannten Methoden getSelect3SelectedValues und getCheckboxlistSelectedValues sind in der Klasse [Form] definiert:
// ausgewählte Werte im Feld „select3“
public String getSelect3SelectedValues() {
return getValue(select3);
}
// ausgewählte Werte im Checkbox-Listenfeld
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// Hilfsmethode
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
Sie fügen lediglich die Elemente der Tabellen zusammen, die sie anzeigen sollen.
9.8. Die Tests
Bei der Ausführung des NetBeans-Projekts erhält man die folgende Startseite:
![]() |
Die in [1] und [2] angezeigten Werte stammen aus den Anfangswerten der Felder der Aktion [Form]. Sehen wir uns einige Beispiele an:
private String textarea = "ligne1\nligne2\n";
Der Wert des Feldes textarea erklärt die Anzeigen in [1A] und [2A].
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
Der Wert des Feldes select3Values erklärt den Inhalt der Liste in [1B]. Der Wert des Feldes select3 erläutert die in [1B] ausgewählten und in [2B] angezeigten Elemente.
Wenn wir weitere Werte in das Formular eingeben und dieses bestätigen, werden die eingegebenen Werte in die entsprechenden Felder der Aktion [Form] übertragen. Anschließend wird die Ansicht [Form.jsp] erneut angezeigt. Wir befinden uns also in derselben Situation wie zuvor, nur dass die ursprünglichen Werte durch die übermittelten Werte ersetzt wurden. Hier ein Beispiel:


9.9. Die Aktion [Form1] und die Ansicht [Form1.jsp]
Die Konfigurationsdatei [example.xml] konfiguriert die folgende Aktion [Form1]:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.jsp</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.jsp</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.jsp</result>
</action>
</package>
</struts>
In den Zeilen 11–13 generiert der Aufruf der Aktion [Form1] die Ansicht [Form1.jsp].
Die Aktion [Form1] lautet wie folgt:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form1 extends ActionSupport{
// Konstruktor ohne Parameter
public Form1() {
}
// Formularfelder
private Data data=new Data();
/**
* @return the data
*/
public Data getData() {
return data;
}
/**
* @param data the data to set
*/
public void setData(Data data) {
this.data = data;
}
}
Die Aktion [Form1] ist identisch mit der Aktion [Form], mit dem Unterschied, dass ihr Modellteil in eine untergeordnete Klasse, die Klasse [Data] (Zeile 11), ausgelagert wurde. Die Klasse [Data] lautet wie folgt:
package example;
public class Data {
// Konstruktor ohne Parameter
public Data() {
}
// Formularfelder
private String textfield = "texte";
private String password = "secret";
private String textarea = "ligne1\nligne2\n";
private String select1 = "zéro";
private String[] select1Values = new String[]{"zéro", "un", "deux"};
private String select2 = "trois";
private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String radio="bleu";
private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
private Boolean checkbox = false;
private String[] checkboxlist = new String[]{"vélo", "bus"};
private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
private String hidden = "initial";
private String submitText;
// ausgewählte Werte im Select3-Feld
public String getSelect3SelectedValues() {
return getValue(select3);
}
// ausgewählte Werte im Checkbox-Listenfeld
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// Hilfsmethode
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// Getter und Setter
....
}
Die zuvor deklarierten Felder finden sich in der Aktion [Form] wieder.
Es ist durchaus logisch, dass die Ansicht [Form1.jsp] der Ansicht [Form.jsp] ähnelt:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="url" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{url}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="url" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{url}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="data.textfield" key="Form.textfield" />
<s:password name="data.password" key="Form.password"/>
<s:textarea name="data.textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="data.select1" list="data.select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="data.select2" size="3" list="data.select2Values" key="Form.select2"/>
<s:select name="data.select3" size="3" list="data.select3Values" key="Form.select3" multiple="true"/>
<s:radio name="data.radio" list="data.radioValues" key="Form.radio"/>
<s:checkbox name="data.checkbox" key="Form.checkbox"/>
<s:checkboxlist name="data.checkboxlist" list="data.checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="data.hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="data.submitText"/>
</s:form>
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="data.textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="data.password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="data.textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="data.select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="data.select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="data.select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="data.radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="data.checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="data.checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="data.hidden"/>
</tr>
</table>
</body>
</html>
Der Unterschied zwischen den Sichten [Form] und [Form1] lässt sich anhand der unten wiedergegebenen Zeile 27 veranschaulichen:
<s:textfield name="data.textfield" key="Form.textfield" />
Das Eingabefeld ist im Lese- und Schreibzugriff mit dem Feld data.textfield der Aktion [Form1] verknüpft. Es sei daran erinnert, dass nach der Ausführung die Eigenschaften der Aktion [Form1] für die Ansicht zugänglich sind. Somit wird das vorangehende Attribut name als [Form1].getData().getTextField() ausgewertet. Daher müssen die beiden vorherigen Methoden get vorhanden sein.
9.10. Die Aktion [Form2] und die Ansicht [Form2.jsp]
Die Konfigurationsdatei [example.xml] konfiguriert die folgende Aktion [Form2]:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.jsp</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.jsp</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.jsp</result>
</action>
</package>
</struts>
In den Zeilen 14–16 generiert der Aufruf der Aktion [Form2] die Ansicht [Form2.jsp].
Die Aktion [Form2] lautet wie folgt:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class Form2 extends ActionSupport implements ModelDriven {
// Konstruktor ohne Parameter
public Form2() {
}
// Aktionsmodell
public Object getModel() {
return new Data();
}
}
- Zeile 6: Die Aktion [Form2] implementiert die Schnittstelle [ModelDriven]. Es muss nur eine Methode implementiert werden, nämlich die Methode getModel in Zeile 12. Diese gibt eine Instanz der zuvor behandelten Klasse [Data] zurück.
Die Tatsache, dass die Aktion [Form2] die Schnittstelle [ModelDriven] implementiert, hat folgende Konsequenz: Die nach der Aktion [Form2] angezeigte Ansicht hat direkten Zugriff auf die Eigenschaften des Modells der Aktion [Form2], da dieses durch die Methode getModel() gerendert wird. Somit kehrt die Ansicht [Form2.jsp] in den Zustand zurück, in dem sie sich bei der ursprünglichen Aktion [Form] befand:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="url" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{url}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="url" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{url}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="textfield" key="Form.textfield" />
<s:password name="password" key="Form.password"/>
<s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
<s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
<s:radio name="radio" list="radioValues" key="Form.radio"/>
<s:checkbox name="checkbox" key="Form.checkbox"/>
<s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="submitText"/>
</s:form>
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="hidden"/>
</tr>
</table>
</body>
</html>
Somit lautet Zeile 27, die zuvor wie folgt aussah:
<s:textfield name="data.textfield" key="Form.textfield" />
wieder zu:
<s:textfield name="textfield" key="Form.textfield" />
Der Vorteil, das Modell außerhalb der Ansicht zu platzieren, besteht darin, dass diese Architektur die Funktionen der einzelnen Elemente der Architektur MVC klarer abgrenzt. Das Modell M wird eindeutig durch eine Klasse identifiziert. Außerdem kann das Modell bereits vor den Aktionen existieren. Wenn also eine Webanwendung eine Personendatenbank verwaltet, ist es wahrscheinlich, dass die Klasse Personne existiert. Wenn eine Aktion ein Eingabeformular zum Anlegen einer neuen Person bereitstellt, liegt das Modell dieser Aktion auf der Hand: Es ist die Klasse Personne.
Wir haben gesehen, wie einfach es war, von der Aktion [Form] zur Aktion [Form2] zu wechseln:
- Das Modell M der Ansicht V wurde in einer separaten Klasse gekapselt
- die Aktion, die die Ansicht unter Verwendung dieses Modells generiert, implementiert die Schnittstelle ModelDriven mit der Methode getModel, die eine Instanz des Modells M zurückgibt. Die Aktion kann somit als Erweiterung des Struts-2-Controllers C, der Klasse FilterDispatcher, betrachtet werden.
Der Leser kann diesen Ansatz auf jede im Folgenden beschriebene Aktion anwenden.

