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


Wir werden das Konzept der Parameterinjektion, das wir für ein Texteingabefeld kennengelernt haben, auf andere HTML-Elemente in einem Formular ausweiten.
9.1. Das NetBeans-Projekt
![]() |
- in [1], die Projektansichten [Formx.jsp]
- in [2], die Struts-Konfigurationsdatei und die internationalisierten Meldungen
- in [3], die Aktionen [Formx.java] und eine weitere Struts-Konfigurationsdatei.
9.2. Struts-Konfiguration
Die Datei [struts.xml] sieht wie folgt aus:
<?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: Fügt eine weitere Konfigurationsdatei [example.xml] ein. Diese Datei konfiguriert die Aktionen.
- Zeilen 11–19: Das Standardpaket. Definiert eine Weiterleitungsadresse für die URL /. Es wird zur URL /example/Form.action weitergeleitet.
Die Datei [example.xml], die die Aktionen konfiguriert, sieht wie folgt aus:
<?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 Sie die Aktionen /example/Form, /example/Form1, /example/Form2, wobei /example der Namespace (Zeile 7) und Formx die Aktionen sind.
- Zeilen 8–10: Durch Ausführen der Aktion Form wird die Ansicht /example/Form.jsp angezeigt.
- Zeilen 11–13: Durch Ausführen der Aktion Form1 wird die Ansicht /example/Form1.jsp angezeigt.
- Zeilen 14–16: Durch Ausführen der Aktion Form2 wird die Ansicht /example/Form2.jsp angezeigt.
9.3. Meldungsdateien
Wir werden nicht näher auf die Internationalisierung des Projekts eingehen. Dies haben wir bereits in Beispiel 01 behandelt. Wir stellen den Inhalt der Datei [messages.properties] zur Verfügung, 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 `action`-Attribut. Dieses Attribut gibt die Aktion an, an die die Formulardaten gesendet werden. Fehlt das `action`-Attribut, werden die Daten an die Aktion gesendet, die die Anzeige der Ansicht ausgelöst hat, in diesem Fall die `[Form]`-Aktion.
- Zeile 27: ein Eingabefeld. Das Attribut `key` gibt dessen Beschriftung an. Das Attribut `name` ist der Name des Parameters, der gesendet wird. Die für dieses Feld gesendete Zeichenfolge hat folgende Form:
textfield=text_entered
Der Parametername entspricht einem Feld in der [Form]-Aktion. Der Wert des Eingabefelds text_saisi wird in das Feld textfield der [Form]-Aktion eingefügt. Umgekehrt gilt: Wenn die Ansicht [Form.jsp] im Anschluss an die Aktion [Form] angezeigt wird, entspricht der Wert des Eingabefelds dem Wert des Felds textfield in der Aktion [Form]. Dieses Feld wird daher sowohl zum Lesen als auch zum Schreiben verwendet. Die Klasse [Form] muss zu diesem Zweck über die Methoden getTextField und setTextField verfügen.
Diese Argumentation gilt für alle nachfolgenden input-Tags. Wir werden sie nicht wiederholen.
- Zeile 28: Passworteingabe. Die an die [Form]-Aktion gesendete Zeichenkette hat die Form
password=entered_password
In der [Form]-Aktion muss ein Passwortfeld mit entsprechenden get/set-Methoden vorhanden sein.
- Zeile 29: Eingabe von mehrzeiligem Text in einem Bereich mit 5 Zeilen und 40 Spalten. Die an die [Form]-Aktion gesendete Zeichenkette hat die Form
textarea=input
In der [Form]-Aktion muss ein Textarea-Feld mit entsprechenden get/set-Methoden vorhanden sein.
- Zeile 30: Eine Dropdown-Liste mit einer Auswahlmöglichkeit (size=1). Es kann nur ein Wert aus der Liste ausgewählt werden. Die an die [Form]-Aktion gesendete Zeichenfolge hat folgende Form:
select1=selected_value
In der [Form]-Aktion muss ein select1-Feld mit seinen 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 [Form]-Aktion aufgerufen, um das Kombinationsfeld zu füllen. Diese Methode kann eine Sammlung, ein Wörterbuch oder ein Array zurückgeben. Hier gibt sie ein Array von Zeichenfolgen [string1, string2, ...] zurück, wodurch der folgende HTML-Code generiert wird:
<option value="string1">string1</option>
<option value="string2">string2</option>
...
Der Text zwischen den Tags <option>...</option> wird in der Kombinationsfeld angezeigt. Das Attribut „value“ gibt den Wert an, der gesendet wird, wenn die Option vom Benutzer ausgewählt wird. Hier sind das Attribut „value“ und der im Kombinationsfeld angezeigte Text identisch. Meistens ist dies jedoch nicht der Fall. Wenn die zweite Option ausgewählt wird, wird die folgende Zeichenfolge an die [Form]-Aktion gesendet:
select1=string2
Das Feld [Form].select1 erhält dann den Wert string2. Umgekehrt gilt: Wenn dieses Feld zum Zeitpunkt der Anzeige des Formulars auf string3 gesetzt ist, wird visuell das dritte Element
<option value="string3">string3</option>
in der Kombinationsfeld optisch als ausgewählt erscheinen.
Das Attribut headerValue legt den Text fest, der als erste Option in der Kombinationsfeld angezeigt werden soll, und headerKey legt den Wert fest, der übermittelt wird, wenn diese Option vom Benutzer ausgewählt wird.
- Zeile 31: erneut eine Liste der Größe 3 (size=3): Im Gegensatz zur vorherigen Liste, bei der nur ein Element sichtbar ist, werden hier 3 Elemente aus der Liste angezeigt. Der Auswahlmodus bleibt derselbe. Es kann nur ein Element ausgewählt werden.
- Zeile 32: eine weitere Liste, diesmal jedoch mit Mehrfachauswahl (multiple=true). In diesem Fall wird der an die [Form]-Aktion übermittelte Wert folgende Form haben:
select3=string2&select3=string5
, sofern die Optionen string2 und string5 ausgewählt wurden. Wenn mehrere Werte für denselben Parameter – in diesem Fall select3 – gesendet werden, muss die Aktion über ein Feld mit dem Namen des Parameters verfügen und vom Typ Array sein. So könnte die [Form]-Aktion hier beispielsweise ein Feld wie das folgende haben:
String[] select3;
sowie die entsprechenden get/set-Methoden. Das select3-Array erhält dann das Array der Zeichenfolgen [string2, string5]. Umgekehrt bestimmen bei der Anzeige der Ansicht [Form.jsp] die Werte des Feldes [Form].select3, welche Optionen in der select3-Liste als ausgewählt erscheinen. Dies ist immer eine Lese-/Schreiboperation.
- Zeile 33: eine Gruppe von Optionsfeldern. Die Gruppenbezeichnung wird durch das Attribut „key“ angegeben. Die Bezeichnungen der einzelnen Schaltflächen werden durch das Attribut „list“ angegeben. Der Wert dieses Attributs ist der Name einer Methode in der [Form]-Aktion, die eine Sammlung, ein Wörterbuch oder ein Array zurückgeben muss. Hier gibt die Methode [Form].getRadioValues ein Array von Zeichenfolgen [string1, string2, ...] zurück, das die folgenden HTML-Tags generiert:
<input type="radio" name="radio" ... value="string1"/>string1
<input type="radio" name="radio" ... value="string2"/>string2
...
Wenn das Optionsfeld string2 ausgewählt ist, lautet der übermittelte Wert
radio=string2
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 [Form]-Aktion gesendet
checkbox=true
Wenn dieses Kontrollkästchen nicht aktiviert ist, wird keine Parameterzeichenfolge übermittelt. Struts 2 verfügt über einen internen Mechanismus, der dafür sorgt, dass alles so abläuft, als ob das Kontrollkästchen
checkbox=false
gesendet worden wäre.
- Zeile 35: eine Liste von Kontrollkästchen. Es können mehrere Kontrollkästchen ausgewählt werden. Die Gruppenbezeichnung 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 in der [Form]-Aktion, die eine Sammlung, ein Dictionary oder ein Array zurückgeben muss. Hier gibt die Methode [Form].getCheckboxlistValues ein Array von Strings [string1, string2, ...] zurück, das die folgenden HTML-Tags generiert:
<input type="checkbox" name="checkboxlist" ... value="string1"/>string1
<input type="checkbox" name="checkboxlist" ... value="string2"/>string2
...
Wenn der Benutzer die Kontrollkästchen mit den Bezeichnungen string2 und string5 auswählt, wird der folgende String an die [Form]-Aktion gesendet:
checkboxlist=string2&checkboxlist=string5
Das Array [string2, string5] wird dem Feld [Form].checkboxlist zugewiesen, das daher wie bei Mehrfachauswahllisten vom Typ String-Array sein muss. Umgekehrt bestimmen bei der Anzeige der Ansicht [Form.jsp] die Werte des Feldes [Form].checkboxlist, welche Kontrollkästchen aktiviert werden.
- Zeile 36: ein verstecktes Feld. Ein verstecktes Feld ist ein Feld, das übermittelt 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 im Formular übermittelt:
hidden=something
und dem Feld [Form].hidden neu zugewiesen.
- Zeile 37: eine Absenden-Schaltfläche. Durch Klicken auf diese Schaltfläche werden alle Formularwerte an die [Form]-Aktion gesendet. Die Zeichenfolge der gesendeten Parameter sieht wie folgt aus:
textfield=text&password=&textarea=line1%0D%0Aline2%0D%0A&select1=zero&select2=three&select3=zero&select3=two&__multiselect_select3=&radio=blue&checkbox=true&__checkbox_checkbox=true&checkboxlist=v%C3%A9lo&checkboxlist=bus&__multiselect_checkboxlist=&hidden=initial&submitText=Validate
9.5. Die [Form]-Aktion – Eingabebereich
Der Code lautet wie folgt:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form extends ActionSupport {
// constructor without parameters
public Form() {
}
// form fields
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;
// values selected in select3 field
public String getSelect3SelectedValues() {
return getValue(select3);
}
// values selected in checkboxlist field
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// utilitarian method
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// field getters and setters
....
}
- Zeile 1: das Feld, das mit dem Textfield-Tag des Formulars verknüpft ist. Dient zur Initialisierung dieses Eingabefelds sowie zum Abrufen seines Werts. Empfängt den Wert, der zum Zeitpunkt der POST-Anfrage in dieses Feld eingegeben wurde.
- Zeile 2: Das Feld, das mit dem password-Tag des Formulars verknüpft ist. Empfängt den Wert, der während der POST-Anfrage in dieses Feld eingegeben wurde.
- Zeile 13: Zugeordnet zum `textarea`-Tag des Formulars. Empfängt den Text, der während der POST-Anfrage in dieses Feld eingegeben wurde.
- Zeile 14: Zugeordnet zum `select1`-Tag des Formulars, einer Einfachauswahlliste. Sein Anfangswert wählt ein Element aus der Dropdown-Liste aus. Das Element mit einem `value`-Attribut, das diesem Wert entspricht, wird ausgewählt. Bei einer POST-Anfrage empfängt es das `value`-Attribut der in der Dropdown-Liste ausgewählten Option.
- Zeile 15: Die Zeichenfolgen, die das „select1“-Dropdown-Menü füllen.
- Zeilen 16 und 17: Wie select1
- Zeile 18: Verbunden mit dem `select1`-Tag des Formulars, eine Mehrfachauswahlliste. Die Anfangswerte im Array wählen die entsprechenden Elemente in der Liste aus. Die Elemente, deren `value`-Attribut mit einem dieser Werte übereinstimmt, werden ausgewählt. Bei einem POST-Aufruf erhält es die `value`-Attribute der verschiedenen in der Dropdown-Liste ausgewählten Optionen.
- Zeile 19: Die Zeichenfolgen, die die Liste „select3“ füllen
- Zeile 20: Verknüpft mit dem radio-Tag des Formulars. Sein Wert wird verwendet, um eines der Optionsfelder auszuwählen – nämlich dasjenige, dessen value-Attribut mit diesem Wert übereinstimmt. Empfängt den Wert des ausgewählten Optionsfelds während der POST-Anfrage.
- Zeile 21: Die verschiedenen Beschriftungen und Werte der Radiobuttons.
- Zeile 22: Verknüpft mit dem Checkbox-Tag des Formulars. Sein Anfangswert wird verwendet, um das Kontrollkästchen zu aktivieren oder zu deaktivieren. Bei einem POST-Aufruf erhält es den Wert „true“, wenn das Kontrollkästchen aktiviert war, andernfalls „false“.
- Zeile 23: Ist mit dem Checkboxlist-Tag des Formulars verknüpft. Die Anfangswerte im Array wählen die entsprechenden Kontrollkästchen aus. Die Kontrollkästchen, deren Wert-Attribut mit einem dieser Anfangswerte übereinstimmt, werden aktiviert. Bei einem POST-Aufruf erhält es die Wert-Attribute der verschiedenen aktivierten Kontrollkästchen.
- Zeile 24: Die Zeichenfolgen, die die Beschriftungen der Checkboxen der Checkbox-Liste füllen.
- Zeile 25: Ist mit dem versteckten Feld verknüpft. Sein Anfangswert legt den Wert des versteckten Feldes fest. Bei einem POST-Aufruf erhält es denselben Wert, da der Benutzer ihn nicht ändern kann.
- Zeile 26: Ist mit dem Submit-Tag verknüpft. Während der POST-Anfrage empfängt es die Beschriftung der Schaltfläche. Dieses Feld ist optional.
- Die Methoden in den Zeilen 29, 34 und 39 werden weiter unten näher erläutert.
9.6. Die Ansicht [Form.jsp] – Abschnitt „Bestätigung“
Die Ansicht [Form.jsp] enthält einen Abschnitt „Bestätigung der Eingaben“, auf den bisher noch nicht eingegangen 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 Feldes [Form].textfield an
- Zeile 17: Zeigt den Wert des Feldes [Form].password an
- Zeile 21: Zeigt den Wert des Feldes [Form].textarea an
- Zeile 25: Zeigt den Wert des Feldes [Form].select1 an
- Zeile 29: Zeigt den Wert des Felds [Form].select2 an
- Zeile 33: Zeigt die Werte des Arrays [Form].select3 an. Dazu wird die Methode [Form].getSelect3SelectedValues verwendet.
- 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. Dazu wird die Methode [Form].getCheckboxlistSelectedValues verwendet.
- Zeile 49: Zeigt den Wert des Felds [Form].hidden an
9.7. Die [Form]-Aktion – Bestätigungsabschnitt
Die oben erwähnten Methoden getSelect3SelectedValues und getCheckboxlistSelectedValues sind in der Klasse [Form] definiert:
// valeurs sélectionnées dans champ select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// valeurs sélectionnées dans champ checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// méthode utilitaire
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
Sie fügen einfach die Elemente der Arrays zusammen, die sie anzeigen möchten.
9.8. Tests
Wenn das NetBeans-Projekt ausgeführt wird, wird die folgende Startseite angezeigt:
![]() |
Die in [1] und [2] angezeigten Werte stammen aus den Anfangswerten der Felder in der [Form]-Aktion. Sehen wir uns einige Beispiele an:
private String textarea = "ligne1\nligne2\n";
Der Wert des Felds „textarea“ erklärt die Anzeigen [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 erklärt die ausgewählten Elemente in [1B] und die in [2B] angezeigten Elemente.
Wenn wir andere Werte in das Formular eingeben und es absenden, werden die eingegebenen Werte an die entsprechenden Felder der [Form]-Aktion übermittelt. Anschließend wird die Ansicht [Form.jsp] erneut angezeigt. Wir befinden uns also in derselben Situation wie zuvor, nur dass die Anfangswerte 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 [Form1]-Aktion:
<?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 11–13: Der Aufruf der Aktion [Form1] generiert die Ansicht [Form1.jsp].
Die Aktion [Form1] lautet wie folgt:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form1 extends ActionSupport{
// constructor without parameters
public Form1() {
}
// form fields
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 separate Klasse, die Klasse [Data], in Zeile 11 verschoben wurde. Die Klasse [Data] sieht wie folgt aus:
package example;
public class Data {
// constructor without parameters
public Data() {
}
// form fields
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;
// values selected in select3 field
public String getSelect3SelectedValues() {
return getValue(select3);
}
// values selected in checkboxlist field
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// utilitarian method
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// getters and setters
....
}
Wir finden die zuvor in der [Form]-Aktion deklarierten Felder.
Logischerweise ähnelt die Ansicht [Form1.jsp] der Ansicht [Form.jsp]:
<%@ 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 Ansichten [Form] und [Form1] lässt sich anhand der unten gezeigten Zeile 27 veranschaulichen:
<s:textfield name="data.textfield" key="Form.textfield" />
Das Eingabefeld ist sowohl für das Lesen als auch für das Schreiben an das Feld „data.textfield“ der Aktion [Form1] gebunden. Erinnern Sie sich daran, dass nach der Ausführung die Eigenschaften der Aktion [Form1] für die Ansicht zugänglich sind. Daher wird das vorangehende Name-Attribut als [Form1].getData().getTextField() ausgewertet. Folglich müssen die beiden vorangehenden get-Methoden vorhanden sein.
9.10. Die Aktion [Form2] und die Ansicht [Form2.jsp]
Die Konfigurationsdatei [example.xml] konfiguriert die folgende [Form2]-Aktion:
<?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 14–16: Der Aufruf der Aktion [Form2] generiert die Ansicht [Form2.jsp].
Die [Form2]-Aktion lautet wie folgt:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class Form2 extends ActionSupport implements ModelDriven {
// constructor without parameters
public Form2() {
}
// action model
public Object getModel() {
return new Data();
}
}
- Zeile 6: Die Aktion [Form2] implementiert die Schnittstelle [ModelDriven]. Es gibt nur eine Methode zu implementieren: die Methode getModel in Zeile 12. Diese Methode gibt eine Instanz der zuvor besprochenen 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], das von der Methode getModel() zurückgegeben wird. Somit kehrt die Ansicht [Form2.jsp] zu dem Zustand zurück, den sie bei der ursprünglichen Aktion [Form] hatte:
<%@ 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>
Also Zeile 27, die zuvor lautete:
<s:textfield name="data.textfield" key="Form.textfield" />
heißt nun:
<s:textfield name="textfield" key="Form.textfield" />
Der Vorteil der Platzierung des Modells außerhalb der Ansicht besteht darin, dass diese Architektur die Funktionen der einzelnen Elemente der MVC-Architektur klarer abgrenzt. Das M-Modell wird eindeutig durch eine Klasse identifiziert. Darüber hinaus kann das Modell bereits vor den Aktionen existieren. Wenn also eine Webanwendung eine Datenbank mit Personen verwaltet, ist es wahrscheinlich, dass die Klasse „Person“ existiert. Wenn eine Aktion ein Eingabeformular zum Anlegen einer neuen Person bereitstellt, ist das Modell für diese Aktion offensichtlich: Es ist die Klasse „Person“.
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 ModelDriven-Schnittstelle mit der getModel-Methode, die eine Instanz des Modells M zurückgibt. Die Aktion kann dann als Erweiterung des Struts-2-Controllers C, der FilterDispatcher-Klasse, betrachtet werden.
Der Leser kann diesen Ansatz auf jede der unten beschriebenen Aktionen anwenden.

