5. Dynamische Formulare mit Integritätsbeschränkungen
Wir werden nun eine neue Anwendung namens strutspersonne2 entwickeln, die
- einem dynamischen Formular wie in strutspersonne1
- einer Datei, die die Integritätsbeschränkungen deklariert, die von den Feldern dieses dynamischen Formulars überprüft werden sollen
5.1. Deklaration von Integritätsbeschränkungen
Die Klasse, die in der Anwendung „strutspersonne1“ zum Speichern der Werte für Name und Alter verwendet wurde, wurde wie folgt deklariert:
<form-beans>
<form-bean name="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
Wir mussten die Klasse „PersonneDynaForm“ schreiben, um eine Validierungsmethode bereitzustellen, die überprüfen kann, ob die Werte für Name und Alter im dynamischen Formular gültig sind. Es waren zwei Arten von Prüfungen durchzuführen:
- Beide Felder dürfen nicht leer sein
- das Feld „Alter“ musste der Maske (regulärem Ausdruck) \s*\d+\s* entsprechen
Diese beiden Validierungen gehören zu den Validierungen, die die StrutsValidator-Umgebung durchführen kann. Diese Umgebung ist im Lieferumfang von Struts enthalten und umfasst eine Reihe von Klassen, die in den Dateien „commons-validator.jar“ und „jakarta-oro.jar“ zu finden sind. Wenn Sie die zu Beginn dieses Dokuments beschriebene Vorgehensweise zur Installation der Struts-Bibliotheken in Tomcat befolgt haben, sind diese Bibliotheken bereits in Tomcat verfügbar. Stellen Sie sicher, dass sie auch in JBuilder verfügbar sind. Dies wurde ebenfalls zu Beginn dieses Dokuments erläutert.
Die neue Formulardeklaration in struts-config.xml sieht nun wie folgt aus:
<form-beans>
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
Es gibt also kaum einen Unterschied. Die mit dem dynamischen Formular verknüpfte Klasse ist nun eine vordefinierte StrutsValidator-Klasse: org.apache.struts.validator.DynaValidatorForm. Der Entwickler muss keine Klasse mehr schreiben. Stattdessen legt er die Integritätsbeschränkungen, die das Formular prüfen muss, in einer separaten XML-Datei fest. Der Struts-Controller muss den Namen dieser Datei kennen. Zu diesem Zweck erscheint ein neuer Konfigurationsabschnitt in der Datei struts-config.xml:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
/>
</plug-in>
Der Abschnitt <plug-in> dient zum Laden einer Klasse außerhalb von Struts. Sein Hauptattribut ist classname, das den Namen der zu instanziierenden Klasse angibt. Das instanziierte Objekt muss möglicherweise initialisiert werden. Dies geschieht mithilfe des set-property-Tags, das zwei Attribute hat:
- property: der Name der zu initialisierenden Eigenschaft
- value: der Wert der Eigenschaft
Hier benötigt die Klasse „DynaValidatorForm“ zwei Informationen:
- die XML-Datei, die die Standard-Integritätsbeschränkungen definiert, die die Klasse validieren kann.
- die XML-Datei, die die Integritätsbeschränkungen für die verschiedenen dynamischen Formulare der Anwendung definiert
Diese Informationen werden hier durch die Eigenschaft „pathnames“ bereitgestellt. Der Wert dieser Eigenschaft ist eine Liste von XML-Dateien, die der Validator laden wird:
- validator-rules.xml ist die Datei, die die Standard-Integritätsbeschränkungen definiert. Sie ist im Lieferumfang von Struts enthalten. Sie befindet sich zusammen mit ihrer DTD-Definitionsdatei in <struts>\lib:
![]()
- validation.xml definiert die Integritätsbeschränkungen für die verschiedenen dynamischen Formulare der Anwendung. Sie wird vom Entwickler erstellt. Ihr Name ist beliebig.
Diese beiden Dateien können an beliebiger Stelle unter WEB-INF abgelegt werden. In unserem Beispiel werden sie direkt unter WEB-INF abgelegt:

5.2. Integritätsbeschränkungen für dynamische Formulare schreiben
Die Datei validation.xml enthält unsere Integritätsbeschränkungen für die Felder „name“ und „age“ des Formulars „frmPersonne“ vom Typ org.apache.struts.validator.DynaValidatorForm. Ihr Inhalt lautet wie folgt:
<form-validation>
<global>
<constant>
<constant-name>entierpositif</constant-name>
<constant-value>^\s*\d+\s*$</constant-value>
</constant>
</global>
<formset>
<form name="frmPersonne">
<field property="nom" depends="required">
<arg0 key="personne.nom"/>
</field>
<field property="age" depends="required,mask">
<arg0 key="personne.age"/>
<var>
<var-name>mask</var-name>
<var-value>${entierpositif}</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
Die folgenden Schreibregeln müssen beachtet werden:
- Alle Regeln sind in einem <form-validation>-Tag enthalten
- Das <global>-Tag wird verwendet, um Informationen mit globalem Geltungsbereich zu definieren, d. h. Informationen, die für alle Formulare gelten, falls mehrere Formulare vorhanden sind. Hier haben wir Konstanten innerhalb von <global> platziert. Eine Konstante wird durch ihren Namen (das <constant-name>-Tag) und ihren Wert (das <constant-value>-Tag) definiert. Wir definieren die Konstante `entierpositif` mit dem regulären Ausdruck, der für eine positive ganze Zahl überprüft werden muss: `_^\s*\d+\s*$` (eine Folge von Ziffern, der möglicherweise Leerzeichen vorangehen und/oder folgen).
- Das <formset>-Tag definiert die Gruppe von Formularen, für die Integritätsbeschränkungen zu prüfen sind
- Das <form name="unFormulaire">-Tag wird verwendet, um die Integritätsbeschränkungen für ein bestimmtes Formular zu definieren, dessen Name durch das name-Attribut angegeben wird. Dieser Name muss in der Liste der in struts-config.xml definierten Formulare vorhanden sein. Hier ist das verwendete Formular frmPersonne in struts-config.xml durch den folgenden Abschnitt definiert:
<form-beans>
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
- Ein Formular-Tag enthält so viele <field>-Tags, wie Integritätsbeschränkungen für das Formular zu prüfen sind. Ein <field>-Tag hat die folgenden Attribute:
- property: Name des Formularfelds, für das Integritätsbeschränkungen definiert sind
- depends: Liste der zu prüfenden Integritätsbeschränkungen.
- Die möglichen Einschränkungen lauten wie folgt: required (das Feld darf nicht leer sein), mask (der Feldwert muss einem durch die Variable „mask“ definierten regulären Ausdruck entsprechen), integer: Der Feldwert muss eine Ganzzahl sein, byte (Byte), long (Long-Ganzzahl), float (Gleitkommazahl mit einfacher Genauigkeit), double (Gleitkommazahl mit doppelter Genauigkeit), short (Short-Ganzzahl), date (der Feldwert muss ein gültiges Datum sein), range (der Feldwert muss innerhalb eines bestimmten Bereichs liegen), email: (der Feldwert muss eine gültige E-Mail-Adresse sein), ...
- Integritätsbeschränkungen werden in der durch das Attribut „depends“ angegebenen Reihenfolge geprüft. Wenn eine Beschränkung fehlschlägt, werden die nachfolgenden nicht geprüft.
- Jede Einschränkung ist mit einer Fehlermeldung verknüpft, die durch einen Schlüssel definiert ist. Hier sind einige Beispiele im Format constraint (Schlüssel): required (errors.required), mask (errors.invalid), integer (errors.integer), byte (errors.byte), long (errors.long), ...
- Die mit den vorgenannten Schlüsseln verbundenen Fehlermeldungen sind in der Datei validator-rules.xml definiert:
# Struts Validator Error Messages
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be a byte.
errors.short={0} must be a short.
errors.integer={0} must be an integer.
errors.long={0} must be a long.
errors.float={0} must be a float.
errors.double={0} must be a double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is an invalid credit card number.
errors.email={0} is an invalid e-mail address.
- Wie oben zu sehen ist, sind die Meldungen auf Englisch. Außerdem sind sie als Kommentare in der Datei enthalten, was angibt, dass sie in die Meldungsdatei der Anwendung aufgenommen werden sollen. Erinnern Sie sich daran, dass dies in einem Abschnitt der Datei struts-config.xml definiert ist:
Das Attribut „parameter“ gibt an, dass sich die Meldungen der Anwendung in der Datei
WEB-INF/classes/resources/personneressources.properties
Fehlermeldungen sollten daher in dieser Datei abgelegt werden. Sie werden zu den bereits vorhandenen hinzugefügt:
personne.formulaire.nom.vide=<li>Vous devez indiquer un nom</li>
personne.formulaire.age.vide=<li>Vous devez indiquer un age</li>
personne.formulaire.age.incorrect=<li>L'âge est incorrect</li>
errors.header=<ul>
errors.footer=</ul>
# Struts Validator error messages
# the key is predefined and must not be changed
# the associated error msg is free
# the msg can have up to 4 parameters {0} to {3}
errors.required=<li>Le champ [{0}] doit être renseigné.</li>
errors.minlength=<li>Le champ [{0}] foit avoir au moins {1} caractère.</li>
errors.maxlength=<li>Le champ [{0}] ne peut avoir plus de {1} caractères.</li>
errors.invalid=<li>Le champ [{0}] est incorrect.</li>
errors.byte=<li>{0} doit être un octet.</li>
errors.short=<li>{0} doit être un entier court.</li>
errors.integer=<li>{0} doit être un entier.</li>
errors.long=<li>{0} doit être un entier long.</li>
errors.float=<li>{0} doit être un réel simple.</li>
errors.double=<li>{0} doit être un réel double.</li>
errors.date=<li>{0} n'est pas une date valide.</li>
errors.range=<li>{0} doit être dans l'intervalle {1} à {2}.</li>
errors.creditcard=<li>{0} n'est pas un numéro de carte valide.</li>
errors.email=<li>{0} n'est pas une adresse électronique valide.</li>
personne.nom=nom
personne.age=age
Gehen wir die Integritätsbeschränkungen in der Datei validation.xml nacheinander durch, um sie zu erklären:
<formset>
<form name="frmPersonne">
<field property="nom" depends="required">
<arg0 key="personne.nom"/>
</field>
...
</form>
</formset>
Beachten Sie, dass diese Integritätsbeschränkungen für die Felder „name“ und „age“ eines in struts-config.xml definierten dynamischen Formulars gelten:
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
Es ist wichtig, dass die Namen des Formulars und seiner Felder in beiden Dateien identisch sind. Die Integritätsbeschränkung für das Feld „name“ (property="name") legt fest, dass das Feld nicht leer sein darf (depends="required"). Ist dies nicht der Fall, wird ein ActionError-Objekt mit dem Schlüssel errors.required generiert. Die diesem Schlüssel zugeordnete Meldung befindet sich in der Datei person.resources.properties:
Wir sehen, dass diese Meldung einen {0}-Parameter verwendet. Sein Wert wird durch das <arg0>-Tag in der Integritätsbeschränkung festgelegt:
Auch hier wird arg0 durch einen Schlüssel bezeichnet, der ebenfalls in der Nachrichten-Datei zu finden ist:
Führt man alles zusammen, lautet die Fehlermeldung, die generiert wird, wenn das Feld „name“ nicht ausgefüllt ist:
Betrachten wir nun die zweite Einschränkung, nämlich die für das Feld „Alter“:
<global>
<constant>
<constant-name>entierpositif</constant-name>
<constant-value>^\s*\d+\s*$</constant-value>
</constant>
</global>
<formset>
<form name="frmPersonne">
...
<field property="age" depends="required,mask">
<arg0 key="personne.age"/>
<var>
<var-name>mask</var-name>
<var-value>${entierpositif}</var-value>
</var>
</field>
</form>
</formset>
Für das Feld „age“ gibt es zwei Einschränkungen: „required“ und „mask“. Wir können die vorherige Erklärung für die Einschränkung „required“ wiederholen. Das bedeutet, dass die mit dieser Einschränkung verbundene Fehlermeldung lautet:
Die zweite Einschränkung ist „mask“. Das bedeutet, dass der Inhalt des Feldes einem Muster entsprechen muss, das durch einen regulären Ausdruck ausgedrückt wird. Der Wert dieser Einschränkung wird in einem <var>-Tag definiert, das eine Variable namens mask (<var-name>) mit dem Wert ${positiveInteger} (<var-value>) definiert. positiveInteger ist eine Konstante, die im <global>-Abschnitt der Datei mit dem Wert des regulären Ausdrucks ^\s*\d+\s*$ definiert ist. Die Integritätsbeschränkung besagt daher, dass das Alter eine Folge aus einer oder mehreren Ziffern sein muss, der optional Leerzeichen vorangestellt oder nachgestellt werden können. Wenn diese Beschränkung nicht erfüllt ist, wird ein ActionError-Objekt mit dem Schlüssel errors.invalid generiert. In der Meldungsdatei ist dieser Schlüssel mit der folgenden Meldung verknüpft:
Die Einschränkung muss einen Wert für den Parameter {0} definieren. Dies geschieht mithilfe des Tags <arg0>:
In der Nachrichtendatei ist der Schlüssel person.age mit der folgenden Nachricht verknüpft:
Die Fehlermeldung, die ausgegeben wird, wenn die Maskenbeschränkung nicht überprüft wird, lautet daher:
5.3. Die Anwendungsklassen
In einer Struts-Anwendung müssen Klassen für Formulare (ActionForm oder davon abgeleitet) und für Aktionen (Action oder davon abgeleitet) geschrieben werden. In der neuen Anwendung strutspersonne2 gibt es keine Klasse für das Formular mehr. Der Formularinhalt wird in struts-config.xml und die zugehörigen Integritätsbeschränkungen in WEB-INF/validation.xml definiert. In der Anwendung strutspersonne1 sah die Klasse FormulaireAction zur Verarbeitung des Formulars wie folgt aus:
package istia.st.struts.personne;
....
public class FormulaireAction
extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException {
// we have a valid form, otherwise we wouldn't have got here
DynaActionForm formulaire=(DynaActionForm)form;
request.setAttribute("nom",formulaire.get("nom"));
request.setAttribute("age",formulaire.get("age"));
return mapping.findForward("reponse");
}//execute
}
Die FormAction-Klasse erwartet, ein Formular in Form eines DynaActionForm-Objekts (boxed code) zu erhalten. In der Datei struts-config.xml ist die Formularklasse jedoch wie folgt definiert:
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
...
</form-bean>
Das Formular wird somit in ein DynaValidatorForm-Objekt eingebettet. Es stellt sich heraus, dass diese Klasse von der DynaActionForm-Klasse abgeleitet ist. Die execute-Methode unserer FormulaireAction-Klasse bleibt daher gültig. Sie muss nicht neu geschrieben werden.
5.4. Bereitstellung und Testen der Anwendung strutspersonne2
5.4.1. Erstellen des Kontexts
Wir haben diese neue Anwendung strutspersonne2 genannt. Wir erstellen eine neue Definition in der Datei <tomcat>\conf\serveur.xml von Tomcat 4.x:
Anschließend muss Tomcat neu gestartet werden. Sie können die Gültigkeit des Kontexts überprüfen, indem Sie die URL aufrufen:
http://localhost:8080/strutspersonne2/

5.4.2. Die Ansichten
Kopieren Sie den Ordner „views“ aus der Anwendung „strutspersonne1“ in den Ordner der Anwendung „strutspersonne2“. Die Ansichten haben sich nicht geändert.

5.4.3. Der Ordner „WEB-INF“
Kopieren Sie den Ordner „WEB-INF“ aus der Anwendung „strutspersonne1“ in den Ordner der Anwendung „strutspersonne2“. Einige Dateien haben sich geändert:

Die Konfigurationsdatei „struts-config.xml“ sieht nun wie folgt aus:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
<action-mappings>
<action
path="/main"
name="frmPersonne"
validate="true"
input="/erreurs.do"
scope="session"
type="istia.st.struts.personne.FormulaireAction"
>
<forward name="reponse" path="/reponse.do"/>
</action>
<action
path="/erreurs"
parameter="/vues/erreurs.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/reponse"
parameter="/vues/reponse.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/formulaire"
parameter="/vues/formulaire.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
</action-mappings>
<message-resources
parameter="ressources.personneressources"
null="false"
/>
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
/>
</plug-in>
</struts-config>
Diese Datei ist identisch mit der in der Anwendung strutspersonne1, abgesehen von der dynamischen Definition des Formulars und der Einbindung des Validierungs-Plugins (eingerahmte Abschnitte).
Fügen Sie die folgende Datei validation.xml zu WEB-INF hinzu:
<form-validation>
<global>
<constant>
<constant-name>entierpositif</constant-name>
<constant-value>^\s*\d+\s*$</constant-value>
</constant>
</global>
<formset>
<form name="frmPersonne">
<field property="nom" depends="required">
<arg0 key="personne.nom"/>
</field>
<field property="age" depends="required,mask">
<arg0 key="personne.age"/>
<var>
<var-name>mask</var-name>
<var-value>${entierpositif}</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
Fügen Sie die Dateien validator-rules.xml und validator-rules_1_1.dtd, die sich in <struts>\lib befinden, zu WEB-INF hinzu:

Im Ordner WEB-INF/classes befindet sich nun nur noch eine Klasse:

Im Ordner WEB-INF\classes\resources finden Sie die folgende Meldungsdatei: personneressources.properties:
personne.formulaire.nom.vide=<li>Vous devez indiquer un nom</li>
personne.formulaire.age.vide=<li>Vous devez indiquer un age</li>
personne.formulaire.age.incorrect=<li>L'âge est incorrect</li>
errors.header=<ul>
errors.footer=</ul>
# Struts Validator error messages
# the key is predefined and must not be changed
# the associated error msg is free
# the msg can have up to 4 parameters {0} to {3}
errors.required=<li>Le champ [{0}] doit être renseigné.</li>
errors.minlength=<li>Le champ [{0}] foit avoir au moins {1} caractère.</li>
errors.maxlength=<li>Le champ [{0}] ne peut avoir plus de {1} caractères.</li>
errors.invalid=<li>Le champ [{0}] est incorrect.</li>
errors.byte=<li>{0} doit être un octet.</li>
errors.short=<li>{0} doit être un entier court.</li>
errors.integer=<li>{0} doit être un entier.</li>
errors.long=<li>{0} doit être un entier long.</li>
errors.float=<li>{0} doit être un réel simple.</li>
errors.double=<li>{0} doit être un réel double.</li>
errors.date=<li>{0} n'est pas une date valide.</li>
errors.range=<li>{0} doit être dans l'intervalle {1} à {2}.</li>
errors.creditcard=<li>{0} n'est pas un numéro de carte valide.</li>
errors.email=<li>{0} n'est pas une adresse électronique valide.</li>
personne.nom=nom
personne.age=age

5.5. Tests
Wir sind bereit für die Tests. Nachfolgend finden Sie einige Screenshots, die der Leser gerne nachstellen kann.
Wir rufen die URL http://localhost:8080/strutspersonne2/formulaire.do auf:

Wir klicken auf die Schaltfläche [Absenden], ohne die Felder auszufüllen:

Wir versuchen es erneut mit einem Fehler im Feld „Alter“:

Wir erhalten folgende Antwort:

Versuchen Sie es erneut und geben Sie diesmal die richtigen Werte ein:

Wir erhalten folgende Antwort:

5.6. Fazit
Wir haben gezeigt, dass die Verwendung dynamischer Formulare mit „Standard“-Integritätsbeschränkungen die Notwendigkeit vermeidet, Klassen zu erstellen, um diese darzustellen. Weichen die Integritätsbeschränkungen vom Standard ab, müssen wir erneut Klassen erstellen, um diese neuen Beschränkungen zu überprüfen.