Skip to content

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 الخاص به:

Image

  • يحدد ملف validation.xml قيود التكامل لمختلف النماذج الديناميكية للتطبيق. يتم إنشاؤه بواسطة المطور. واسمه تعسفي.

يمكن وضع هذين الملفين في أي مكان ضمن WEB-INF. في مثالنا، سيتم وضعهما مباشرةً ضمن WEB-INF:

Image

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.requiredmask (errors.invalidinteger (errors.integerbyte (errors.bytelong (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:
    <message-resources 
      parameter="ressources.personneressources"
    null="false"
  />    

تشير سمة المعلمة إلى أن رسائل التطبيق موجودة في الملف

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:

   errors.required=<li>Le champ [{0}] doit être renseigné.</li>

يمكننا أن نرى أن هذه الرسالة تستخدم معلمة {0}. يتم تعيين قيمتها بواسطة العلامة <arg0> في قيد التكامل:

             <arg0 key="personne.nom"/>      

هنا أيضًا، يتم تعيين arg0 بواسطة مفتاح موجود أيضًا في ملف الرسائل:

   personne.nom=nom

وبجمع كل ذلك معًا، فإن رسالة الخطأ التي يتم إنشاؤها في حالة عدم ملء حقل الاسم هي:

<li>Le champ [nom] doit être renseigné.</li>

دعونا نحلل الآن القيد الثاني، وهو القيد المفروض على حقل العمر:

    <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. وهذا يعني أن رسالة الخطأ المرتبطة بهذا القيد ستكون:

<li>Le champ [age] doit être renseigné.</li>

القيد الثاني هو القناع. وهذا يعني أن محتوى الحقل يجب أن يتطابق مع نمط يتم التعبير عنه بواسطة تعبير عادي. يتم تعريف قيمة هذا القيد في علامة <var> التي تحدد متغيرًا باسم mask (<var-name>) بقيمة ${positiveInteger} (<var-value>). positiveInteger هو ثابت محدد في قسم <global> من الملف بقيمة التعبير العادي ^\s*\d+\s*$. وبالتالي، فإن قيد التكامل هو أن العمر يجب أن يكون تسلسلاً من رقم واحد أو أكثر، يسبقه أو يتبعه مسافات اختيارياً. إذا لم يتم استيفاء هذا القيد، فسيتم إنشاء كائن ActionError بالمفتاح errors.invalid. في ملف الرسائل، يرتبط هذا المفتاح بالرسالة التالية:

   errors.invalid=<li>Le champ [{0}] est incorrect.</li>

يجب أن يحدد القيد قيمة للمعلمة {0}. ويتم ذلك باستخدام العلامة <arg0>:

             <arg0 key="personne.age"/>      

في ملف الرسائل، يرتبط المفتاح person.age بالرسالة التالية:

     personne.age=age

وبالتالي، فإن رسالة الخطأ التي سيتم إنشاؤها في حالة عدم التحقق من قيد القناع هي:

<li>Le champ [age] est incorrect.</li>

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:

                <Context path="/strutspersonne2" docBase="e:/data/serge/web/struts/personne2" />

بمجرد الانتهاء من ذلك، يجب إعادة تشغيل Tomcat. يمكنك التحقق من صحة السياق عن طريق طلب عنوان URL:

http://localhost:8080/strutspersonne2/

Image

5.4.2. طرق العرض

انسخ مجلد views من تطبيق strutspersonne1 إلى مجلد تطبيق strutspersonne2. لم تتغير طرق العرض.

Image

5.4.3. مجلد WEB-INF

انسخ مجلد WEB-INF من تطبيق strutspersonne1 إلى مجلد تطبيق strutspersonne2. وقد تغيرت بعض الملفات:

Image

يصبح ملف التكوين 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:

Image

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

Image

في المجلد 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

Image

5.5. الاختبارات

نحن جاهزون لإجراء الاختبارات. فيما يلي بعض لقطات الشاشة التي ندعو القارئ إلى إعادة إنتاجها.

نطلب عنوان URL http://localhost:8080/strutspersonne2/formulaire.do:

Image

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

Image

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

Image

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

Image

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

Image

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

Image

5.6. الخلاصة

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