5. Динамічні форми з обмеженнями цілісності
Зараз ми розробимо нову програму під назвою strutspersonne2, яка використовує
- динамічну форму, як у strutspersonne1
- файл з оголошенням обмежень цілісності, які мають перевірятися полями цієї динамічної форми
5.1. Оголошення обмежень цілісності
Клас, що використовувався для зберігання значень «ім’я» та «вік» у додатку strutspersonne1, був оголошений наступним чином:
<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>
Нам довелося створити клас PersonneDynaForm, щоб мати метод validate, здатний перевіряти правильність значень полів «ім’я» та «вік» у динамічній формі. Перевірки, які потрібно було виконати, були двох видів:
- обидва поля мали бути заповнені
- поле «age» мало відповідати шаблону (регулярному виразу) \s*\d+\s*
Ці дві перевірки входять до переліку перевірок, які може виконувати середовище StrutsValidator. Це середовище постачається разом із Struts і містить певну кількість класів, які можна знайти в commons-validator.jar та jakarta-oro.jar. Якщо ви дотрималися процедури встановлення бібліотек Struts у Tomcat, описаної на початку цього документа, ці бібліотеки вже доступні в Tomcat. Переконайтеся, що вони також доступні в JBuilder. Це також було пояснено на початку цього документа.
Нова декларація форми у файлі struts-config.xml має такий вигляд:
<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>
Отже, різниця дуже незначна. Клас, пов'язаний із динамічною формою, тепер є попередньо визначеним класом StrutsValidator: org.apache.struts.validator.DynaValidatorForm. Розробнику більше не потрібно писати клас. Він вказує обмеження цілісності, які має перевіряти форма, в окремому файлі XML. Контролер Struts повинен знати ім’я цього файлу. Для цього у файлі 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>
Розділ <plug-in> служить для завантаження класу, зовнішнього щодо Struts. Його основним атрибутом є classname, який вказує ім'я класу, що підлягає інстанціюванню. Інстанційований об'єкт може потребувати ініціалізації. Це здійснюється за допомогою тегів set-property, які мають два атрибути:
- property: ім’я властивості, яку потрібно ініціалізувати
- value: значення властивості
У цьому випадку класу DynaValidatorForm потрібно знати дві речі:
- файл XML, який визначає стандартні обмеження цілісності, перевірку яких клас може здійснювати;
- файл XML, що визначає обмеження цілісності різних динамічних форм додатка
Ці дві інформації тут надаються властивістю pathnames. Значенням цієї властивості є список файлів XML, які завантажить валідатор:
- validator-rules.xml — це файл, що визначає стандартні обмеження цілісності. Він постачається разом із Struts. Його можна знайти в папці <struts>\lib разом із файлом визначення DTD:
![]()
- validation.xml визначає обмеження цілісності різних динамічних форм додатка. Його створює розробник. Назва файлу може бути довільною.
Ці два файли можна розмістити в будь-якому місці під WEB-INF. У нашому прикладі вони будуть розміщені безпосередньо під WEB-INF:

5.2. Запис обмежень цілісності динамічних форм
Файл validation.xml міститиме наші обмеження цілісності для полів «ім’я» та «вік» форми frmPersonne типу org.apache.struts.validator.DynaValidatorForm. Його вміст такий:
<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>
Необхідно дотримуватися таких правил написання:
- усі правила містяться у тезі <form-validation>
- Тег <global> використовується для визначення інформації глобального обсягу, c.a.d. Вона діє для всіх форм, якщо їх декілька. Тут у тег <global> введено константи. Константа визначається своїм іменем (тег <constant-name>) та значенням (тег <constant-value>). Ми визначаємо константу «entierpositif» із значенням у вигляді регулярного виразу, якому має відповідати додатне ціле число: ^\s*\d+\s*$ (послідовність цифр, перед якою та/або після якої можуть бути пробіли).
- тег <formset> визначає набір форм, для яких необхідно перевірити обмеження цілісності
- тег <form name="unFormulaire"> слугує для визначення вимог до цілісності конкретної форми, ім’я якої вказано в атрибуті name. Це ім’я має бути присутнім у списку форм, визначених у struts-config.xml. У даному випадку використовувана форма frmPersonne визначена у файлі struts-config.xml у наступному розділі:
<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> містить стільки тегів <field>, скільки існує обмежень цілісності, які потрібно перевірити для форми. Тег <field> має такі атрибути:
- property: ім’я поля форми, для якого визначаються обмеження цілісності
- depends: список обмежень цілісності, які потрібно перевірити.
- Можливі обмеження такі: required (поле має бути заповненим), mask (значення поля має відповідати регулярному виразу, визначеному змінною mask), integer: значення поля має бути цілим числом, byte (байт), long (довге ціле число), float (просте дійсне число), double (подвійне дійсне число), short (коротке ціле число), date (значення поля має бути дійсною датою), range (значення поля має бути в заданому діапазоні), email: (значення поля має бути дійсною адресою електронної пошти), ...
- перевірка обмежень цілісності відбувається у порядку, заданому атрибутом depends. Якщо одне обмеження не проходить перевірку, наступні не перевіряються.
- кожна обмеження пов’язана з повідомленням про помилку, визначеним за допомогою ключа. Ось декілька прикладів у форматі «обмеження (ключ)»: required (errors.required), mask (errors.invalid), integer (errors.integer), byte (errors.byte), long (errors.long), ...
- повідомлення про помилки, пов’язані з попередніми ключами, визначені у файлі validator-rules.xml:
# Повідомлення про помилки Struts Validator
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.
- Як бачимо вище, повідомлення написані англійською мовою. Крім того, вони містяться у коментарях до файлу, де зазначено, що їх потрібно помістити у файл повідомлень програми. Нагадаємо, що цей файл визначено в розділі файлу struts-config.xml:
Атрибут parameter вказує, що повідомлення додатка містяться у файлі
WEB-INF/classes/ressources/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
# ключ задано за замовчуванням і його не слід змінювати
# відповідне повідомлення про помилку є вільним
# повідомлення може мати до 4 параметрів: від {0} до {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
Розглянемо обмеження цілісності файлу validation.xml по черзі, щоб пояснити їх:
<formset>
<form name="frmPersonne">
<field property="nom" depends="required">
<arg0 key="personne.nom"/>
</field>
...
</form>
</formset>
Нагадаємо, що ці обмеження щодо цілісності застосовуються до полів «ім'я» та «вік» динамічної форми, визначеної в struts-config.xml:
<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>
Важливо, щоб назви форми та її полів були однаковими в обох файлах. Обмеження цілісності для поля «ім’я» (property="nom") передбачає, що поле має бути заповненим (depends="required"). Якщо це не так, буде згенеровано об’єкт ActionError із ключем errors.required. Повідомлення, пов’язане з цим ключем, міститься у файлі personne.ressources.properties:
Бачимо, що це повідомлення використовує параметр {0}. Його значення визначається тегом <arg0> обмеження цілісності:
І тут arg0 позначається ключем, який також міститься у файлі повідомлень:
Якщо з’єднати все це разом, повідомлення про помилку, яке генерується, якщо поле «nom» не заповнене, буде таким:
Тепер проаналізуємо друге обмеження, яке стосується поля «age»:
<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>
Для поля age існують два обмеження: required та mask. Можна повторити попереднє пояснення щодо обмеження required. Отже, повідомлення про помилку, пов’язане з цим обмеженням, буде таким:
Друге обмеження — mask. Це означає, що вміст поля має відповідати шаблону, заданому регулярним виразом. Значення останнього визначається в тезі <var>, що визначає змінну з іменем mask (<var-name>), значення якої дорівнює ${entierpositif} (<var-value>). entierpositif — це константа, визначена в розділі <global> файлу, значенням якої є регулярний вираз ^\s*\d+\s*$. Отже, обмеження цілісності полягає в тому, що вік має бути послідовністю однієї або декількох цифр, перед якими або після яких можуть бути пробіли. Якщо це обмеження не виконується, буде згенеровано об’єкт ActionError із ключем errors.invalid. У файлі повідомлень цей ключ пов’язаний із таким повідомленням:
Обмеження має визначати значення для параметра {0}. Це здійснюється за допомогою тегу <arg0>:
У файлі повідомлень ключ personne.age пов’язаний із таким повідомленням:
Отже, повідомлення про помилку, яке буде згенеровано, якщо обмеження mask не буде перевірено, має такий вигляд:
5.3. Класи додатка
У додатку Struts потрібно створювати класи форм (ActionForm або похідні від нього) та класи дій (Action або похідні від нього). У новому додатку strutspersonne2 більше немає класу для форми. Вміст форми визначається у struts-config.xml, а відповідні обмеження цілісності — у WEB-INF/validation.xml. У додатку strutspersonne1 клас FormulaireAction для обробки форми мав такий вигляд:
package istia.st.struts.personne;
....
public class FormulaireAction
extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException {
// форма є дійсною, інакше ми б не дійшли до цього місця
DynaActionForm formulaire=(DynaActionForm)form;
request.setAttribute("nom",formulaire.get("nom"));
request.setAttribute("age",formulaire.get("age"));
return mapping.findForward("reponse");
}//виконати
}
Клас FormulaireAction очікував отримати форму у вигляді об’єкта DynaActionForm (код у рамці). Однак у файлі struts-config.xml клас форми визначено так:
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
...
</form-bean>
Отже, форма буде розміщена в об’єкті типу DynaValidatorForm. Виявляється, що цей клас є похідним від класу DynaActionForm. Тому метод execute нашого класу FormulaireAction залишається дійсним. Його не потрібно переписувати.
5.4. Розгортання та тестування додатка strutspersonne2
5.4.1. Створення контексту
Ми назвали цей новий додаток strutspersonne2. Створюємо нове визначення у файлі <tomcat>\conf\serveur.xml Tomcat 4.x:
Після цього потрібно перезапустити Tomcat. Перевірити правильність налаштування контексту можна, звернувшись до URL:
http://localhost:8080/strutspersonne2/

5.4.2. Види
Ми скопіюємо папку «vues» з додатка strutspersonne1 у папку додатка strutspersonne2. Адже види не змінилися.

5.4.3. Папка WEB-INF
Скопіюємо папку WEB-INF з додатка strutspersonne1 у папку додатка strutspersonne2. Деякі файли змінилися:

Файл конфігурації struts-config.xml набуває такого вигляду:
<?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>
Цей файл ідентичний файлу додатка strutspersonne1, за винятком динамічного визначення форми та вставки плагіна перевірки (виділені фрагменти).
До WEB-INF додаємо такий файл перевірки validation.xml:
<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>
До WEB-INF додаємо файли validator-rules.xml, validator-rules_1_1.dtd, які знаходяться в <struts>\lib:

У папці WEB-INF/classes залишився лише один клас:

У папці WEB-INF\classes\ressources знаходиться такий файл повідомлень 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
# ключ є заздалегідь визначеним і не повинен змінюватися
# відповідне повідомлення про помилку є вільним
# повідомлення може мати до 4 параметрів: від {0} до {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. Тестування
Ми готові до тестів. Нижче наведено кілька знімків екрана, які читач може спробувати відтворити.
Потрібно виконати URL http://localhost:8080/strutspersonne2/formulaire.do:

Використовуємо кнопку [Envoyer], не заповнюючи поля:

Повторюємо спробу, але з помилкою у полі «age»:

Отримуємо таку відповідь:

Повторюємо спробу, цього разу вказавши правильні значення:

Отримуємо таку відповідь:

5.6. Висновок
Ми показали, що використання динамічних форм, для яких обмеження цілісності є «стандартними», дозволяє уникнути створення класів для їхнього представлення. Якщо ж обмеження цілісності виходять за межі стандарту, доводиться знову створювати класи для перевірки цих нових обмежень.