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 قادرة على التحقق من صحة قيم الاسم والعمر في النموذج الديناميكي. كان هناك نوعان من الفحوصات التي يجب إجراؤها:
- يجب ألا يكون أي من الحقلين فارغًا
- يجب أن يتطابق حقل العمر مع القناع (التعبير العادي) \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> لتعريف المعلومات ذات النطاق العام، أي الصالحة لجميع النماذج في حالة وجود نماذج متعددة. هنا، وضعنا الثوابت داخل <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>
- تحتوي علامة النموذج على عدد من علامات <field> يساوي عدد قيود التكامل التي يجب التحقق منها في النموذج. تحتوي علامة <field> على السمات التالية:
- property: اسم حقل النموذج الذي تم تعريف قيود التكامل له
- depends: قائمة بقيود التكامل التي يجب التحقق منها.
- القيود المحتملة هي كما يلي: مطلوب (يجب ألا يكون الحقل فارغًا)، قناع (يجب أن تتطابق قيمة الحقل مع تعبير عادي محدد بواسطة متغير القناع)، عدد صحيح: يجب أن تكون قيمة الحقل عددًا صحيحًا، بايت (بايت)، لونج (عدد صحيح طويل)، عائم (عدد عائم بدقة مفردة)، مزدوج (عدد عائم بدقة مزدوجة)، قصير (عدد صحيح قصير)، تاريخ (يجب أن تكون قيمة الحقل تاريخًا صالحًا)، نطاق (يجب أن تكون قيمة الحقل ضمن نطاق معين)، بريد إلكتروني: (يجب أن تكون قيمة الحقل عنوان بريد إلكتروني صالحًا)، ...
- يتم فحص قيود التكامل بالترتيب المحدد بواسطة السمة depends. إذا فشل أحد القيود، فلن يتم اختبار القيود اللاحقة.
- يرتبط كل قيد برسالة خطأ محددة بواسطة مفتاح. فيما يلي بعض الأمثلة بتنسيق القيد (المفتاح): required (errors.required)، mask (errors.invalid)، integer (errors.integer)، byte (errors.byte)، long (errors.long)، ...
- يتم تعريف رسائل الخطأ المرتبطة بالمفاتيح السابقة في ملف validator-rules.xml:
# 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.
- كما نرى أعلاه، الرسائل باللغة الإنجليزية. علاوة على ذلك، تم تضمينها كتعليقات في الملف، مما يحدد أنه يجب وضعها في ملف رسائل التطبيق. تذكر أن هذا محدد في قسم من ملف struts-config.xml:
تشير سمة المعلمة إلى أن رسائل التطبيق موجودة في الملف
WEB-INF/classes/resources/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
دعونا نستعرض قيود التكامل في ملف 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="name") أنه يجب ألا يكون الحقل فارغًا (depends="required"). إذا لم يكن الأمر كذلك، فسيتم إنشاء كائن ActionError بمفتاح errors.required. توجد الرسالة المرتبطة بهذا المفتاح في ملف person.resources.properties:
يمكننا أن نرى أن هذه الرسالة تستخدم معلمة {0}. يتم تعيين قيمتها بواسطة العلامة <arg0> في قيد التكامل:
هنا أيضًا، يتم تعيين arg0 بواسطة مفتاح موجود أيضًا في ملف الرسائل:
وبجمع كل ذلك معًا، فإن رسالة الخطأ التي يتم إنشاؤها في حالة عدم ملء حقل الاسم هي:
دعونا نحلل الآن القيد الثاني، وهو القيد المفروض على حقل العمر:
<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>
هناك قيدان لحقل العمر: required و mask. يمكننا تكرار الشرح السابق الخاص بقيد required. وهذا يعني أن رسالة الخطأ المرتبطة بهذا القيد ستكون:
القيد الثاني هو القناع. وهذا يعني أن محتوى الحقل يجب أن يتطابق مع نمط يتم التعبير عنه بواسطة تعبير عادي. يتم تعريف قيمة هذا القيد في علامة <var> التي تحدد متغيرًا باسم mask (<var-name>) بقيمة ${positiveInteger} (<var-value>). positiveInteger هو ثابت محدد في قسم <global> من الملف بقيمة التعبير العادي ^\s*\d+\s*$. وبالتالي، فإن قيد التكامل هو أن العمر يجب أن يكون تسلسلاً من رقم واحد أو أكثر، يسبقه أو يتبعه مسافات اختيارياً. إذا لم يتم استيفاء هذا القيد، فسيتم إنشاء كائن ActionError بالمفتاح errors.invalid. في ملف الرسائل، يرتبط هذا المفتاح بالرسالة التالية:
يجب أن يحدد القيد قيمة للمعلمة {0}. ويتم ذلك باستخدام العلامة <arg0>:
في ملف الرسائل، يرتبط المفتاح person.age بالرسالة التالية:
وبالتالي، فإن رسالة الخطأ التي سيتم إنشاؤها في حالة عدم التحقق من قيد القناع هي:
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 {
// 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
}
تتوقع فئة FormAction استلام نموذج على شكل كائن 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. طرق العرض
انسخ مجلد views من تطبيق 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، باستثناء التعريف الديناميكي للنموذج وإدراج المكون الإضافي للتحقق من الصحة (الأقسام الموضوعة في مربعات).
أضف ملف validation.xml التالي إلى WEB-INF:
<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>
أضف الملفين validator-rules.xml و validator-rules_1_1.dtd، الموجودين في <struts>\lib، إلى WEB-INF:

في مجلد WEB-INF/classes، يوجد الآن فئة واحدة فقط:

في المجلد WEB-INF\classes\resources، ستجد ملف الرسائل التالي، 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. الاختبارات
نحن جاهزون لإجراء الاختبارات. فيما يلي بعض لقطات الشاشة التي ندعو القارئ إلى إعادة إنتاجها.
نطلب عنوان URL http://localhost:8080/strutspersonne2/formulaire.do:

نضغط على زر [إرسال] دون ملء الحقول:

نحاول مرة أخرى مع وجود خطأ في حقل العمر:

نتلقى الرد التالي:

حاول مرة أخرى، مع إدخال القيم الصحيحة هذه المرة:

نحصل على الرد التالي:

5.6. الخلاصة
لقد أظهرنا أن استخدام النماذج الديناميكية مع قيود التكامل "القياسية" يغني عن الحاجة إلى إنشاء فئات لتمثيلها. إذا انحرفت قيود التكامل عن المعيار، فسنضطر مرة أخرى إلى إنشاء فئات للتحقق من هذه القيود الجديدة.