5. فرمهای پویا با محدودیتهای یکپارچگی
اکنون قصد داریم یک برنامه جدید به نام strutspersonne2 را با استفاده از
- یک فرم پویا مانند strutspersonne1
- یک فایل که محدودیتهای یکپارچگی را که باید توسط فیلدهای این فرم پویا بررسی شوند، اعلام میکند
5.1. اعلام محدودیتهای یکپارچگی
کلاسی که برای ذخیره مقادیر 'name' و 'age' در برنامه 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 را داشته باشیم که قادر باشد مقادیر «name» و «age» در فرم پویا را بررسی کند. دو نوع بررسی باید انجام میشد:
- هر دو فیلد باید غیرخالی باشند
- میدان '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 شامل محدودیتهای یکپارچگی ما برای فیلدهای «name» و «age» فرم 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)، تاریخ (مقدار فیلد باید یک تاریخ معتبر باشد)، بازه (مقدار فیلد باید در یک بازه مشخص قرار داشته باشد)، ایمیل: (مقدار فیلد باید یک آدرس ایمیل معتبر باشد)، ...
- محدودیتهای یکپارچگی به ترتیبی که توسط ویژگی `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/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
#کلید از پیش تعریف شده است و نباید تغییر کند
# پیام خطای مرتبط مشخص نشده است
# پیام میتواند تا ۴ پارامتر داشته باشد {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>
لطفاً توجه داشته باشید که این محدودیتهای یکپارچگی برای فیلدهای «name» و «age» یک فرم پویا که در 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>
مهم است که نامهای فرم و فیلدهای آن در هر دو فایل یکسان باشند. محدودیت یکپارچگی روی فیلد 'name' (property="name") مشخص میکند که این فیلد نباید خالی باشد (depends="required"). اگر اینطور نباشد، یک شیء ActionError با کلید errors.required ایجاد خواهد شد. پیام مرتبط با این کلید را میتوان در فایل personne.ressources.properties یافت:
میتوانیم ببینیم که این پیام از پارامتر {0} استفاده میکند. مقدار آن توسط تگ <arg0> در محدودیت یکپارچگی تعیین میشود:
در اینجا نیز، arg0 با کلیدی شناسایی میشود که در فایل پیام نیز یافت میشود:
اگر همه اینها را کنار هم قرار دهیم، پیام خطایی که در صورت پر نکردن فیلد «name» تولید میشود، به این صورت است:
اکنون بیایید محدودیت دوم، یعنی آن که مربوط به فیلد «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 است. این بدان معناست که محتوای field باید با الگویی که توسط یک عبارت منظم بیان شده مطابقت داشته باشد. مقدار این محدودیت در تگ <var> تعریف میشود که متغیری به نام mask (<var-name>) را با مقدار ${positiveInteger} (<var-value>) تعریف میکند. positiveInteger یک ثابت است که در بخش <global> فایل تعریف شده و مقدار آن عبارت منظم ^\s*\d+\s*$ است. بنابراین، محدودیت یکپارچگی این است که سن باید یک دنباله از یک یا چند رقم باشد که ممکن است قبل یا بعد از آن فضاهای خالی قرار داشته باشد. اگر این محدودیت رعایت نشود، یک شیء با نام ActionError و کلید errors.invalid ایجاد خواهد شد. در فایل پیام، این کلید با پیام زیر مرتبط است:
محدودیت باید یک مقدار برای پارامتر {0} تعریف کند. این کار با استفاده از تگ <arg0> انجام میشود:
در فایل پیام، کلید personne.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 {
// ما یک فرم معتبر داریم؛ در غیر این صورت تا اینجا نمیرسیدیم
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 <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
#کلید از پیش تعریف شده است و نباید تغییر کند
# پیام خطای مرتبط مشخص نشده است
# پیام میتواند تا ۴ پارامتر داشته باشد {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. آزمایشها
ما برای آزمونها آمادهایم. در زیر چند اسکرینشات آمده است که از خواننده دعوت میشود آنها را بازتولید کند.
ما در جستجوی URLhttp://localhost:8080/strutspersonne2/formulaire.do هستیم:

از دکمه [Envoyer] بدون پر کردن فیلدها استفاده کنید:

ما دوباره تلاش میکنیم، اما در فیلد «سن» خطایی وجود دارد:

پاسخ زیر بازگردانده میشود:

بیایید دوباره تلاش کنیم، این بار با وارد کردن مقادیر صحیح:

پاسخ زیر دریافت میشود:

5.6. نتیجهگیری
نشان دادیم که استفاده از فرمهای پویا با محدودیتهای یکپارچگی «استاندارد»، نیاز به ایجاد کلاس برای نمایش آنها را از بین میبرد. اگر محدودیتهای یکپارچگی از استاندارد انحراف داشته باشند، در این صورت مجدداً ملزم به ایجاد کلاس برای اعتبارسنجی این محدودیتهای جدید هستیم.