Skip to content

6. نماذج HTML

حتى الآن، استخدمنا نموذجًا واحدًا يحتوي على حقلين للإدخال فقط. هنا، نقترح إنشاء ومعالجة نموذج باستخدام مكونات رسومية قياسية (أزرار الاختيار، مربعات الاختيار، حقول الإدخال، مربعات القائمة المنسدلة، القوائم).

6.1. طرق عرض التطبيق

سيكون للتطبيق عرضان فقط. يعرض الأول نموذجًا فارغًا:

العرض 1 - النموذج

Image

ستسمح لنا هذه الواجهة الأولى، المسماة form.jsp، بتنفيذ علامات متنوعة من مكتبة struts-html. يقوم المستخدم بملء النموذج:

Image

يؤكد زر [إرسال] القيم التي تم إدخالها. وسيكون هذا هو العرض الثاني:

Image

ستسمح لنا هذه الشاشة الثانية باستخدام مكتبتين أخريين للعلامات: struts-bean و struts-logic. يتيح لنا الرابط [العودة إلى النموذج] العودة إلى النموذج كما قمنا بملئه. ثم نعود إلى الشاشة الأولى.

6.2. بنية التطبيق

  • سيتم تمثيل النموذج (الطريقة 1) بواسطة كائن Struts ديناميكي يُسمى dynaFormulaire، وهو فئة فرعية من DynaActionForm. وسيتم عرضه بواسطة طريقة العرض form.jsp.
  • وستكون عملية Struts InitFormulaireAction مسؤولة عن استرداد البيانات اللازمة لعرض النموذج
  • سيتم معالجة النموذج المكتمل بواسطة ForwardAction، والتي ستقوم ببساطة بإعادة توجيه الطلب إلى العرض الثاني، confirmation.jsp. وسيكون هذا العرض مسؤولاً عن عرض قيم النموذج.

6.3. تكوين التطبيق

6.3.1. ملف server.xml

سيتم تسمية سياق التطبيق بـ /formulaire2. لذلك سنضيف السطر التالي إلى ملف server.xml الخاص بـ Tomcat:

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

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

Image

6.3.2. ملف web.xml

سيكون ملف تكوين web.xml الخاص بالتطبيق كما يلي:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <servlet>
      <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
      <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
  </taglib>

</web-app>

بالمقارنة مع ملفات التكوين web.xml التي رأيناها سابقًا، نقوم بإجراء بعض التغييرات:

  • نقدم مكتبتين جديدتين للعلامات: struts-bean و struts-logic. وسيتم استخدامهما في عرض confirmation.jsp. أما عرض formulaire.jsp، فسيستخدم مكتبة struts-html.

6.3.3. ملف struts-config.xml

سيكون ملف 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="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                  
        </form-bean>            
    </form-beans>

    <action-mappings>
      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

    </action-mappings>

        <message-resources 
      parameter="ApplicationResources"
        null="false"/>    

</struts-config>

يحتوي على ثلاثة أقسام رئيسية:

  • إعلان النماذج في قسم <form-beans>
  • إعلان الإجراءات في قسم <action-mappings>
  • إعلان ملف الموارد في <message-resources>

6.3.4. كائنات نماذج التطبيق (البيانات)

الكائنات المستخدمة لتمثيل نماذج HTML الخاصة بالتطبيق هي من نوع ActionForm أو نوع مشتق (DynaActionForm، DynaValidatorForm، إلخ). وتسمى هذه الكائنات beans لأن بنائها يتبع قواعد JavaBeans. يوجد نموذج bean واحد فقط في تطبيقنا، يسمى dynaFormulaire ومشتق من DynaActionForm. وسيتم استخدامه في الحالات التالية:

  • لاحتواء البيانات اللازمة لعرض العرض رقم 1
  • لاسترداد القيم من النموذج في العرض رقم 1 عندما يرسله المستخدم
  • لاحتواء البيانات اللازمة لعرض العرض رقم 2

ترتبط بنية bean dynaFormulaire ارتباطًا وثيقًا بالنموذج في العرض رقم 1. دعونا نفحصها:

رقم
نوع HTML
الدور
1
<input name="opt" type="radio" value="yes">
<input name="opt" type="radio" value="no">
مجموعة من أزرار الاختيار المرتبطة ببعضها (نفس الاسم)
2
<input name="chk1" type="radio" value="on">
<input name="chk2" type="radio" value="on">
<input name="chk3" type="radio" value="on">
مجموعات من مربعات الاختيار
(ليس الاسم نفسه)
3
<input type="text" name="inputField">
حقل نصي
4
<input type="password" name="password">
حقل كلمة مرور
5
<textarea name="inputBox">...</textarea>
حقل إدخال متعدد الأسطر
6
<select name="combo" size="1">..</select>
قائمة منسدلة
7
<select name="simpleList" size="3">..</select>
قائمة اختيار واحد
8
<select name="listeMultiple" size="3" multiple>..</select>
قائمة اختيار متعددة
9
<input type="button" value="مسح"
onclick='clearList("singleList")'>
زر لإلغاء تحديد
العناصر المحددة في simpleList (7)
10
<input type="button" value="مسح"
onclick='clearList("multipleList")'>
زر لإلغاء تحديد
العناصر المحددة في multipleList (8)
11
<input type="submit" value="إرسال">
زر إرسال النموذج
12
<input type="hidden" name="secret" value="...">
حقل مخفي

لننظر في عدة حالات:

  1. يُستخدم كائن dynaFormulaire لتخزين القيم من نموذج HTML أعلاه، والتي سيتم إرسالها عبر زر [إرسال]. لذلك يجب أن يحتوي على نفس الحقول الموجودة في نموذج HTML. يتم تحديد نوع الحقل وفقًا للقاعدة التالية:
  • إذا كان حقل HTML يوفر قيمة واحدة فقط، فسيكون حقل dynaFormulaire من النوع java.lang.String
  • إذا كان حقل HTML يوفر قيمًا متعددة، فسيكون حقل dynaFormulaire من النوع java.lang.String[]

في نموذج HTML أعلاه، يمكن ربط الحقل listeMultiple فقط بقيم متعددة (تلك التي يختارها المستخدم). لذلك، سيكون التعريف الأولي لكائن **dynaFormulaire** كما يلي:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
        </form-bean>            

كيف سيتم ملء dynaFormulaire بقيم نموذج HTML المرسلة من عميل الويب؟

opt
سيتلقى حقل opt القيمة "yes" إذا تم تحديد حقل HTML <input type="radio" name="opt" value="yes">، والقيمة "no" إذا تم تحديد الحقل <input type="radio" name="opt" value="no">.
chk1
سيتلقى حقل chk1 القيمة "on" إذا تم تحديد حقل HTML <input name="chk1" type="radio" value="1">؛ وإلا، فلن يتلقى أي شيء. في الحالة الأخيرة، سيحتفظ حقل chk1 بقيمته السابقة.
chk2
same
chk3
نفس
حقل الإدخال
سيتلقى الحقل `champSaisie` النص الذي أدخله المستخدم في حقل HTML `<input type="text" name="champSaisie">`. قد يكون هذا النص سلسلة فارغة.
كلمة المرور
سيتلقى الحقل mdp النص الذي أدخله المستخدم في حقل HTML <input type="password" name="mdp">. قد يكون هذا النص سلسلة فارغة.
textarea
سيتلقى حقل inputBox النص الذي أدخله المستخدم في حقل HTML <textarea name="inputBox">...</textarea>. يشكل هذا النص سلسلة واحدة، تتكون من الأسطر التي كتبها المستخدم مفصولة عن بعضها البعض بتسلسل الأحرف "\r\n". قد يكون النص الناتج، اختيارياً، سلسلة فارغة.
combo
سيتلقى حقل combo الخيار الذي يختاره المستخدم في حقل HTML <select name="combo" size="1">..</select>. الخيار المحدد هو الذي يظهر في مربع combo. إذا كان خيار HTML المحدد من النوع <option value="XX">YY</option>، فسيتلقى حقل combo القيمة "XX". إذا كان الخيار HTML المحدد من النوع <option>YY</option>، فسيتلقى حقل القائمة المنسدلة القيمة "YY".
simpleList
سيتلقى حقل simpleList الخيار الذي يختاره المستخدم في حقل HTML <select name="simpleList" size="..">..</select> إذا كان هناك خيار. إذا لم يكن هناك خيار، فلن يتلقى حقل simpleList أي قيمة وسيحتفظ بقيمته السابقة. تتبع القيمة المخصصة فعليًا لحقل simpleList القواعد المحددة لمربع القائمة المنسدلة.
listeMultiple
سيتلقى الحقل listeMultiple من النوع String[] الخيارات التي يختارها المستخدم في حقل HTML <select name="listeMultiple" size=".." multiple>..</select> إن وجدت. وفي حالة عدم وجود أي خيارات، لن يتلقى المصفوف listeMultiple أي قيمة وسيظل محتواه دون تغيير. وتتبع القيم المخصصة فعليًا لمصفوف listeMultiple القواعد المحددة لمربع القائمة المنسدلة.
secret
سيتلقى الحقل secret القيمة XX من حقل HTML <input type="hidden" name="secret" value="XX">. قد يكون هذا النص، بشكل اختياري، سلسلة فارغة.
  1. يُستخدم كائن dynaFormulaire لتوفير المحتوى الأولي للعرض رقم 1. ستُستخدم قيم الحقول السابقة للأغراض التالية:
opt
يجب أن يكون له القيمة "yes" أو "no" حتى يعرف المتصفح زر الاختيار الذي يجب تحديده
chk1
إذا كانت قيمة chk1 هي "on"، فسيتم تحديد مربع الاختيار؛ وإلا، فلن يتم تحديده
chk2
نفس
chk3
نفس
حقل الإدخال
سيتم عرض قيمة الحقل في حقل الإدخال fieldInput
كلمة المرور
سيتم عرض قيمة الحقل في حقل إدخال mdp
مربع الإدخال
سيتم عرض قيمة الحقل في مربع الإدخال inputBox
combo
تشير قيمة هذا الحقل إلى العنصر الذي يجب تحديده في مربع القائمة المنسدلة عند عرض النموذج
قائمة بسيطة
same
قائمة متعددة
تشير القيم الموجودة في مصفوفة multipleList إلى العناصر التي يجب تحديدها في القائمة المتعددة عند عرض النموذج
secret
سيتم تعيين قيمة الحقل إلى سمة value لحقل HTML السري.

العرض رقم 1 يتطلب معلومات إضافية:

  • قائمة القيم المراد عرضها في القائمة المنسدلة
  • قائمة القيم المراد عرضها في قائمة `listeSimple`
  • قائمة القيم المراد عرضها في قائمة multipleList

هناك عدة طرق لتزويد العرض بهذه المعلومات. على سبيل المثال، يمكن استخدام المصفوفات الموضوعة في الطلب الذي يتم تمريره إلى العرض. هنا، نضع هذه المصفوفات في حبة dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                  
        </form-bean>            

سيتم تهيئة النموذج dynaFormulaire بواسطة الإجراء /init، الذي سيستدعي كائنًا مشتقًا من Action يسمى InitFormulaireAction. سيكون هذا الكائن مسؤولاً عن إنشاء المصفوفات الثلاث اللازمة لعرض القوائم الثلاث ووضعها في حبة dynaFormulaire. يحدد ملف التكوين نطاق هذه الحبة على session. ونتيجة لذلك، سيضع وحدة التحكم Struts هذه الحبة في الجلسة. وبالتالي، لن نحتاج إلى إعادة إنشائه بين دورات الطلب والاستجابة. وبالتالي، سيتم استدعاء الإجراء /init مرة واحدة فقط.

  1. يُستخدم كائن dynaFormulaire أيضًا لملء العرض رقم 2. يعرض هذا العرض القيم ببساطة.

6.3.5. إجراءات التطبيق

يتم التعامل مع الإجراءات بواسطة كائنات من نوع Action أو الأنواع المشتقة. يتم تكوين الإجراء داخل علامات <action-mappings>:

    <action-mappings>
      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

    </action-mappings>

لاحظ أنه لا يوجد دائمًا نموذج مرتبط بعمل ما. وهذا هو الحال، أعلاه، مع العمل /affiche. قبل تفصيل كل عمل، دعونا نستعرض كيف يعمل الزوج "العمل-النموذج" داخل علامة <action>:

  • تبدأ العملية بطلب من عميل الويب وتنتهي بإرسال صفحة استجابة. وهذه هي دورة الطلب والاستجابة بين العميل والخادم في الويب. يستقبل الطلب وحدة التحكم Struts من نوع ActionServlet أو فئة مشتقة منها. وتقوم وحدة التحكم هذه أيضًا بإرسال الاستجابة.
  • يتم إنشاء حبة النموذج من النوع ActionForm أو فئة مشتقة إذا لم تكن موجودة بالفعل. تتحقق وحدة التحكم مما إذا كان بإمكانها العثور على كائن باسم name في النطاق المحدد بواسطة scope. إذا كان الأمر كذلك، فإنها تستخدمه. إذا لم يكن الأمر كذلك، فإنها تنشئه وتضعه في النطاق المحدد بواسطة scope، مرتبطًا بالسمة المحددة بواسطة name.

في مثال الإجراء /init، على سبيل المثال، ستستدعي وحدة التحكم request.getSession().getAttribute("dynaFormulaire") لتحديد ما إذا كان dynaFormulaire قد تم إنشاؤه بالفعل أم لا. إذا لم يكن كذلك، فستقوم بإنشائه وإضافته إلى الجلسة باستخدام عبارة مثل request.getSession().setAttribute("dynaFormulaire", new DynaFormulaire(...)).

  • ستبحث وحدة التحكم أيضًا عن كائن Action من النوع المحدد بواسطة السمة type. إذا لم تجده، فستقوم بإنشائه؛ وإلا، فستستخدمه.
  • سيتم استدعاء طريقة reset الخاصة بـ form bean. يتم إعادة استخدام هذا bean، باستثناء أثناء إنشائه الأولي. لذلك، فإنه يحتوي على بيانات قد ترغب في "تنظيفها". يتم ذلك في طريقة reset الخاصة بـ ActionForm bean أو فئة مشتقة.
  • إذا كان الإجراء هو هدف نموذج تم إرساله، فسيتم نسخ قيم النموذج الموجودة في طلب العميل إلى الحقول التي تحمل نفس الاسم في حبة النموذج. لاحظ أن طريقة إعادة الضبط تم استدعاؤها قبل هذا النسخ.
  • إذا حددت التهيئة السمة validate="true"، فسيتم استدعاء طريقة validate الخاصة بـ bean النموذج. يجب أن تقوم هذه الطريقة بعد ذلك بالتحقق من صحة البيانات الموجودة في bean. عادةً ما يحدث هذا التحقق من الصحة فقط عندما يكون النموذج قد تلقى للتو بيانات جديدة عبر نموذج مرسَل وتريد التحقق من صحة تلك البيانات. تُرجع هذه الطريقة أي قائمة بالأخطاء إلى وحدة التحكم في كائن ActionErrors.
  • إذا لم يكن كائن ActionErrors فارغًا، يعرض وحدة التحكم العرض المحدد بواسطة سمة الإدخال الخاصة بالإجراء.
  • إذا لم يكن التحقق من صحة البيانات مطلوبًا أو إذا كان ناجحًا، يستدعي وحدة التحكم طريقة `execute` الخاصة بكائن `Action` (أو فئة مشتقة) المرتبط بالإجراء الحالي. تتم معالجة طلب عميل الويب ضمن هذه الطريقة. تُرجع طريقة `execute` كائن `ActionForward` مفهرسًا بمفاتيح سلسلة. هذه المفاتيح هي تلك المُعلنة بواسطة علامات `forward` للإجراء المُهيأ. في مثالنا، يحتوي الإجراء `/init` على علامة `forward` واحدة. وهي تربط المفتاح "displayForm" بعرض `form.jsp`.
  • يعرض وحدة التحكم العرض المرتبط بالمفتاح المستلم. قد يكون هذا العرض في الواقع إجراءً، وفي هذه الحالة تتكرر العملية السابقة.

الإجراء /init

        <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>
  • عادةً ما تحدث الإجراء /init مرة واحدة خلال دورة الطلب والاستجابة الأولى عندما يطلب المستخدم عنوان URL http://localhost:8080/formulaire2/init.do
  • يتم إنشاء كائن dynaForm أو إعادة استخدامه. يتم استرجاعه (إعادة الاستخدام) أو وضعه (الإنشاء) في الجلسة وفقًا لما تحدده سمة النطاق.
  • يتم استدعاء طريقة إعادة تعيينه. ما الذي يجب أن يفعله؟ عادةً، يتم إعادة تعيين حقول كائن ActionForm إلى القيم الافتراضية. ومع ذلك، في هذه الحالة، لن نقوم بذلك، لأن كائن dynaFormulaire يتم وضعه في الجلسة (scope="session"). لذلك يجب أن تحتفظ حقول dynaFormulaire بقيمها. ما هي هذه القيم أثناء الإنشاء الأولي لكائن dynaFormulaire؟ هناك حالتان:
  • يحتوي الحقل على قيمة أولية محددة في ملف التكوين:
            <form-property name="opt" type="java.lang.String" initial="non"/>

في هذه الحالة، سيقوم وحدة التحكم Struts بإنشاء هذا الحقل بهذه القيمة الأولية.

  • إذا لم يتم تحديد قيمة أولية للحقل في التكوين: تُطبق قواعد التهيئة في Java. بشكل عام، ستكون قيمة الحقول الرقمية صفرًا، وستكون قيمة السلاسل سلسلة فارغة، وستكون قيمة الكائنات الأخرى null.

دعونا نلقي نظرة على التكوين الأولي لـ dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>             
        </form-bean>            

ستكون القيم الأولية لحقول dynaFormulaire بعد الإنشاء كما يلي:

الحقل
القيمة الأولية
opt
"لا"
chk1، chk2، chk3
سلسلة فارغة
حقل الإدخال
سلسلة فارغة
mdp
سلسلة فارغة
مربع الإدخال
سلسلة فارغة
قائمة منسدلة
سلسلة فارغة
قائمة بسيطة
سلسلة فارغة
قائمة متعددة
مصفوفة من السلاسل الفارغة
سر
"xxx"
comboValues، singleList، multipleList
مصفوفة من سلاسل فارغة
  • قد يتصور المرء أن طريقة إعادة التعيين في dynaFormulaire تعين قيمًا للمصفوفات الثلاث التي تملأ القوائم الثلاث في عرض formulaire.jsp. قد يكون هذا ممكنًا هنا لأن البيانات في هذه المصفوفات الثلاث يتم إنشاؤها بشكل عشوائي. ومع ذلك، فإن السيناريو الأكثر شيوعًا هو أن هذه البيانات تأتي من نموذج التطبيق، وهو الحرف M في MVC. هنا، سنتخذ موقفًا وسطًا — للحفاظ على بساطة المثال — من خلال إنشاء هذه القيم بواسطة الإجراء InitFormulaireAction، أي بواسطة الحرف C في MVC.
  • ليس هناك حاجة لكتابة طريقة إعادة تعيين في dynaFormulaire، لأن فئة ActionForm التي تنحدر منها تحتوي بالفعل على طريقة لا تفعل شيئًا (لا توجد عمليات تهيئة).
  • بمجرد استدعاء طريقة إعادة الضبط في dynaFormulaire، يتحقق وحدة التحكم من سمة التحقق من صحة الإجراء. هنا، تكون القيمة "false". لن يتم استدعاء طريقة التحقق من صحة dynaFormulaire.
  • يتم إنشاء كائن InitFormulaireAction أو إعادة استخدامه إذا كان موجودًا بالفعل، ويتم استدعاء طريقة execute الخاصة به. تخصص هذه الطريقة قيمًا عشوائية للمصفوفات الثلاثة في dynaFormulaire: valeursCombo و valeursListeSimple و valeursListeMultiple. تُرجع الطريقة ActionForward بالمفتاح "afficherFormulaire".
  • يعرض وحدة التحكم عرض /vues/formulaire.jsp، الذي تم ربطه بالمفتاح "afficherFormulaire" عبر علامة إعادة توجيه من الإجراء /init.

إجراء /confirmation

      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • يحدث الإجراء /confirmation عندما ينقر المستخدم على زر [Submit] في العرض رقم 1. ثم يقوم المتصفح بـ"إرسال" النموذج الذي ملأه المستخدم إلى وحدة التحكم Struts.
  • يتم استرداد كائن dynaFormulaire من الجلسة
  • يتم استدعاء طريقة إعادة التعيين الخاصة بها. وبمجرد استدعائها، تقوم وحدة التحكم Struts بنسخ قيم حقول النموذج التي أرسلها العميل إلى الحقول التي تحمل نفس الأسماء في dynaFormulaire. دعونا نستعرض قائمة الحقول في dynaFormulaire ونرى كيف تتم عملية النسخ هذه:
الحقل
كود HTML المرتبط
قيمة الحقل
بعد نسخ قيم النموذج
opt
<input type="radio" name="opt" value="yes">نعم
<input type="radio" name="opt" value="no" checked="checked">لا
- "نعم" أو "لا" حسب زر الاختيار المحدد
chk1
<input type="checkbox" name="chk1" value="on">
- "on" إذا تم تحديد مربع الاختيار chk1
- يحتفظ بقيمته السابقة إذا لم يتم تحديد مربع الاختيار chk1
chk2
<input type="checkbox" name="chk2" value="on">
- "on" إذا تم تحديد مربع الاختيار chk2
- يحتفظ بقيمته السابقة إذا لم يتم تحديد مربع الاختيار chk2
chk3
<input type="checkbox" name="chk2" value="on">
- "on" إذا تم تحديد مربع الاختيار chk3
- يحتفظ بقيمته السابقة إذا لم يتم تحديد مربع الاختيار chk3
حقل الإدخال
<input type="text" name="inputField" value="">
- القيمة التي أدخلها المستخدم في inputField
password
<input type="password" name="password" value="">
- القيمة التي أدخلها المستخدم في حقل كلمة المرور
مربع الإدخال
<textarea name="inputBox"></textarea>
- القيمة التي أدخلها المستخدم في textbox
combo
<select name="combo">...</select>
- القيمة التي يختارها المستخدم في القائمة المنسدلة
قائمة بسيطة
<select name="simpleList" size="3">...</select>
- القيمة التي اختارها المستخدم في قائمة بسيطة
multipleList
<select name="listeMultiple" multiple="multiple" size="5">
- مصفوفة من السلاسل تحتوي على القيم التي اختارها المستخدم في multipleList
secret
<input type="hidden" name="secret" value="xxx">
- "xxx".

نواجه مشكلة مع الحقول التي لا تتلقى بالضرورة قيمة في الطلب المرسل من المتصفح. ينطبق هذا على مربعات الاختيار chk1 إلى chk3 والقائمتين listeSimple و listeMultiple. في هذه الحالة، تحتفظ هذه الحقول بقيمها السابقة — تلك التي تم الحصول عليها خلال دورة الطلب والاستجابة السابقة.

لنأخذ مربع الاختيار chk1 كمثال، ولنفترض أن المستخدم قد حدد هذا المربع في دورة الطلب والاستجابة السابقة. عندئذ أرسل المتصفح المعلومات chk1="on" في سلسلة معلمات طلبه. وبالتالي، قام مُنشئ الكائن بتعيين القيمة "on" لحقل chk1 في dynaFormulaire. والآن، لنفترض أن المستخدم لم يحدد مربع الاختيار chk1 في الدورة الحالية. في هذه الحالة، في سلسلة معلمات الطلب الجديد، لا يرسل المتصفح شيئًا مثل chk1="off" بل لا يرسل أي شيء. ونتيجة لذلك، سيحتفظ حقل chk1 في dynaFormulaire بقيمته "on" وبالتالي سيكون له قيمة لا تعكس قيمة النموذج الذي تم التحقق من صحته من قبل المستخدم. سنستخدم طريقة إعادة الضبط في dynaFormulaire لحل هذه المشكلة. في هذه الطريقة، سنقوم بتعيين الحقول الثلاثة chk1 و chk2 و chk3 على "off". في مثال chk1 الخاص بنا، إما أن يقوم المستخدم:

  • يحدد مربع الاختيار chk1. في هذه الحالة، يرسل المتصفح المعلومات chk1="on" وسيتغير حقل chk1 في dynaFormulaire إلى "on"
  • أو لا يحدد مربع الاختيار chk1. عندئذٍ لا يرسل المتصفح قيمة لحقل chk1، والذي سيحتفظ بقيمته السابقة "off". في كلتا الحالتين، تكون القيمة المخزنة في حقل chk1 في dynaFormulaire صحيحة.

المشكلة مشابهة لكل من قوائم simpleList و multiList. إذا لم يتم تحديد أي خيار في هذه القوائم، فلن تكون موجودة في معلمات الطلب وبالتالي ستحتفظ بقيمها السابقة. في طريقة إعادة الضبط في dynaFormulaire، سنقوم بإعادة ضبط simpleList بسلسلة فارغة و multiList بمصفوفة من السلاسل بطول 0.

  • بمجرد استدعاء طريقة إعادة تعيين dynaFormulaire، يقوم وحدة التحكم بنسخ المعلومات المرسلة إليها في طلب العميل مرة أخرى إلى حقول dynaFormulaire
  • يتم إنشاء كائن ForwardAction أو إعادة استخدامه، ويتم استدعاء طريقة execute الخاصة به. ForwardAction هي فئة محددة مسبقًا تعيد كائن ActionForward يشير إلى العرض المحدد بواسطة سمة "parameter" الخاصة بالإجراء، وفي هذه الحالة /vues/confirmation.jsp.
  • يرسل وحدة التحكم هذا العرض. وبذلك يكتمل الدورة.

/display

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • يتم تشغيل الإجراء /display بالنقر على رابط [العودة إلى النموذج] في العرض رقم 2.
  • هنا، لا يوجد نموذج مرتبط بالإجراء. لذلك ننتقل مباشرة إلى تنفيذ طريقة `execute` لكائن `ForwardAction`، والتي ستُرجع كائن `ActionForward` يشير إلى العرض `/vues/formulaire.jsp`.

6.3.6. ملف رسائل التطبيق

القسم الثالث من ملف struts-config.xml هو ملف الرسائل:

        <message-resources 
          parameter="ApplicationResources"
            null="false"
      />    

يوجد ملف ApplicationResources.properties في WEB-INF/classes. وسيكون فارغًا. على الرغم من أنه فارغ، إلا أنه يجب الإعلان عنه في ملف التكوين؛ وإلا، فإن مكتبة علامات struts-bean، التي سنناقشها لاحقًا، ستولد خطأً. يتم استخدام هذه المكتبة بواسطة عرض confirmation.jsp.

6.4. كود العرض

6.4.1. عرض formulaire.jsp

تذكر أن هذا العرض يظهر في حالتين:

  • عند استدعاء الإجراء /init خلال دورة الطلب والاستجابة الأولى
  • عند استدعاء الإجراء /affiche خلال الدورات اللاحقة

فيما يلي كود عرض formulaire.jsp:

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html>
  <head>
      <title>formulaire</title>
  </head>  
  <body background='<html:rewrite page="/images/standard.jpg"/>'>
      <h3>Formulaire Struts</h3>
    <hr>
    <html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
      <table border="0">
        <tr>
          <td>bouton radio</td>
          <td>
                        <html:radio name="dynaFormulaire" property="opt" value="oui">Oui</html:radio>
                        <html:radio name="dynaFormulaire" property="opt" value="non">Non</html:radio>                                            
          </td>
        </tr>
        <tr>
          <td>Cases à cocher</td>
          <td>
                        <html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
                        <html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
                        <html:checkbox name="dynaFormulaire" property="chk3">3</html:checkbox>                                                
          </td>
        </tr>
        <tr>
          <td>Champ de saisie</td>
          <td>
                        <html:text name="dynaFormulaire" property="champSaisie" />
          </td>
        </tr>
        <tr>
          <td>Mot de passe</td>
          <td>
              <html:password name="dynaFormulaire" property="mdp" />
          </td>
        </tr>
        <tr>
          <td>Boîte de saisie multilignes</td>
          <td>
              <html:textarea name="dynaFormulaire" property="boiteSaisie" />
          </td>
        </tr>
        <tr>
          <td>Combo</td>
          <td>
              <html:select name="dynaFormulaire" property="combo">
                            <html:options name="dynaFormulaire" property="valeursCombo"/>
                        </html:select>
          </td>
        </tr>
        <tr>
          <td>
                        <table>
                            <tr>
                                <td>Liste à sélection unique</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>
                                </td>
                            </tr>
                        </table>
          <td>
              <html:select name="dynaFormulaire" property="listeSimple" size="3">
                            <html:options name="dynaFormulaire" property="valeursListeSimple"/>                        
                        </html:select>
          </td>
        </tr>
        <tr>
                    <td>
                        <table>
                            <tr>
                                <td>Liste à sélection multiple</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>                                
                                </td>
                            </tr>
                        </table>
                    </td>
          <td>
              <html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
                            <html:options name="dynaFormulaire" property="valeursListeMultiple"/>                        
                        </html:select>
          </td>
        </tr>
      </table>
      <html:hidden name="dynaFormulaire" property="secret"/>
            <br>
            <hr>
            <html:submit>Envoyer</html:submit> 
    </html:form>
  </body>
</html>

تستخدم صفحة JSP هذه علامات من مكتبة struts-html. تذكر أنه لاستخدام مكتبة العلامات، يجب عليك:

  • تعلنها في ملف web.xml الخاص بالتطبيق باستخدام علامة <tag-lib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  • ضع كود هذه المكتبة في مكان ما ضمن شجرة دليل التطبيق، هنا WEB-INF/struts-html.tld
  • أعلن استخدام هذه المكتبة في بداية صفحات JSP التي تستخدمها:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

تستخدم طريقة العرض formulaire.jsp علامات سنشرحها الآن:

العلامة
<body background="<html:rewrite page="/images/standard.jpg"/>">
ترجمة HTML
<body background="/formulaire2/images/standard.jpg">
شرح
تسمح لك علامة html:rewrite بحذف اسم التطبيق من عناوين URL. ولها سمة واحدة:
page
عنوان URL المراد إعادة كتابته
لذا، في المثال أعلاه، إذا قررت تسمية التطبيق "form3"، فلن تحتاج إلى إعادة كتابة كود سمة الخلفية. ستقوم علامة `html:rewrite` بإنشاء كود HTML الجديد
background="/formulaire3/images/standard.jpg"
علامة
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
ترجمة HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
شرح
تقوم علامة html:form بإنشاء علامة النموذج HTML. ولها عدة سمات:
action
إجراء Struts الذي يجب إرسال النموذج إليه — يجب أن يتوافق مع أحد الإجراءات المحددة في struts-config.xml
name
اختياري - اسم حبة ActionForm أو فئة فرعية منها يجب وضع قيم النموذج المرسَل فيها أو قراءتها. إذا تم حذف هذه السمة، يتم استخدام النموذج المرتبط بالإجراء المحدد بواسطة سمة action. توجد هذه المعلومات في ملف التكوين (سمة name للإجراء).
النوع
اختياري - فئة Java التي سيتم إنشاء مثيل لها للنموذج. إذا تم حذف هذه السمة، فسيتم استخدام الفئة المرتبطة بالإجراء المحدد بواسطة السمة action. توجد هذه المعلومات في ملف التكوين (السمة type الخاصة بالإجراء).
يمكننا أن نلاحظ أنه بشكل افتراضي، يستخدم كود HTML الذي تم إنشاؤه طريقة POST. في كود HTML هذا نفسه، تمت إعادة كتابة عنوان URL الخاص بالإجراء بحيث يبدأ باسم التطبيق وينتهي بـ .do.
العلامة
<html:radio name="dynaFormulaire" property="opt" value="yes">نعم</html:radio>
ترجمة HTML
<input type="radio" name="opt" value="yes">
شرح
تُستخدم علامة html:radio لإنشاء علامة HTML <input type="radio" ...>. وهي تدعم العديد من السمات:
name
اختياري - اسم حبة ActionForm أو الحبة المشتقة التي يجب وضع قيمة الحقل فيها أو قراءتها. إذا تم حذف هذه السمة، يتم استخدام النموذج المرتبط بعلامة <html:form>.
property
اسم الحقل في bean النموذج المرتبط بزر الاختيار للقراءة والكتابة.
القيمة
اختياري - القيمة المراد تعيينها لحقل HTML
النص الموجود بين علامتي البداية والنهاية هو النص الذي سيتم عرضه بجانب زر الاختيار.
علامة
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
ترجمة HTML
<input type="checkbox" name="chk1" value="on">
شرح
تُستخدم علامة html:checkbox لإنشاء علامة HTML <input type="checkbox" ...>. وهي تدعم العديد من السمات:
name
اختياري - اسم حبة ActionForm أو الحبة المشتقة التي يجب وضع قيمة الحقل فيها أو قراءتها. إذا تم حذف هذه السمة، يتم استخدام النموذج المرتبط بعلامة <html:form>.
property
اسم الحقل في bean النموذج المرتبط بمربع الاختيار للقراءة والكتابة.
القيمة
اختياري - القيمة المراد تعيينها لحقل HTML
النص الموجود بين علامتي البداية والنهاية هو النص الذي سيتم عرضه بجانب مربع الاختيار.
علامة
<html:text name="dynaFormulaire" property="inputField" />
ترجمة HTML
<input type="text" name="inputField" value="">
شرح
تُستخدم علامة html:text لإنشاء علامة HTML <input type="text" ...>. وهي تدعم العديد من السمات:
name
اختياري - اسم كائن ActionForm أو الكائن المشتق منه الذي يجب وضع قيمة الحقل فيه أو قراءتها منه. إذا تم حذف هذه السمة، يتم استخدام النموذج المرتبط بعلامة <html:form>.
الخاصية
اسم الحقل في bean النموذج المرتبط بحقل الإدخال للقراءة والكتابة.
القيمة
اختياري - القيمة المراد تعيينها لحقل HTML
علامة
<html:password name="dynaFormulaire" property="mdp" />
ترجمة HTML
<input type="password" name="mdp" value="">
شرح
تُستخدم علامة html:password لإنشاء علامة HTML <input type="password" ...>. وهي تدعم العديد من السمات:
علامة
<html:textarea name="dynaFormulaire" property="boiteSaisie" />
ترجمة HTML
<textarea name="boiteSaisie"></textarea>
شرح
تُستخدم علامة HTML:textarea لإنشاء علامة HTML <textarea>...</textarea>. وهي تدعم العديد من السمات:
name
اختياري - اسم حبة ActionForm أو الحبة المشتقة التي يجب وضع قيمة الحقل فيها أو قراءتها. إذا تم حذف هذه السمة، يتم استخدام النموذج المرتبط بعلامة <html:form>.
property
اسم الحقل في bean النموذج المرتبط بحقل كلمة المرور للقراءة والكتابة.
القيمة
اختياري - القيمة المراد تعيينها لحقل HTML
علامة
<html:select name="dynaFormulaire" property="combo">....</html:select>
ترجمة HTML
<select name="combo">...</select>
شرح
تُستخدم علامة HTML:select لإنشاء علامة HTML <select>...</select>. وهي تدعم العديد من السمات:
name
اختياري - اسم حبة ActionForm أو الحبة المشتقة التي يجب وضع قيمة الحقل فيها أو قراءتها. إذا تم حذف هذه السمة، يتم استخدام النموذج المرتبط بعلامة <html:form>.
property
اسم الحقل في bean النموذج المرتبط بحقل الإدخال للقراءة والكتابة.
القيمة
اختياري - القيمة المراد تعيينها لحقل HTML. سيتم تحديد خيار مربع القائمة المنسدلة الذي يحتوي على هذه القيمة.
علامة
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="comboValues"/>
</html:select>
ترجمة HTML
<option value="combo1">combo1</option>
<option value="combo2">combo2</option>

شرح
تُستخدم علامة HTML:options لإنشاء علامات HTML <option>...</option> داخل علامة HTML <select>. هناك طرق مختلفة لتحديد كيفية العثور على القيم لملء عنصر الاختيار. هنا، استخدمنا سمات الاسم والخاصية:
name
اختياري - اسم حبة ActionForm أو الحبة المشتقة التي يجب وضع قيمة الحقل فيها أو قراءتها. إذا تم حذف هذه السمة، يتم استخدام النموذج المرتبط بعلامة <html:form>.
property
اسم الحقل في bean النموذج الذي يحتوي على قيم الاختيار. يجب أن يكون هذا مصفوفة من سلاسل الأحرف.

يتم إنشاء القائمتين الأخريين بطريقة مشابهة للقائمة السابقة:

          <html:select name="dynaFormulaire" property="listeSimple" size="3">
            <html:options name="dynaFormulaire" property="valeursListeSimple"/>            
        </html:select>

في الأعلى، نحدد سمة حجم غير 1 لإنشاء قائمة بدلاً من مربع قائمة منسدلة.

<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
        <html:options name="dynaFormulaire" property="valeursListeMultiple"/>                
    </html:select>

في الأعلى، نحدد السمة multiple="true" لإنشاء قائمة ذات اختيارات متعددة.

العلامة
<html:hidden name="dynaFormulaire" property="secret"/>
ترجمة HTML
<input type="hidden" name="secret" value="xxx">
شرح
تُستخدم علامة html:hidden لإنشاء علامة HTML <input type="hidden" ...>.
الاسم
اختياري - اسم حبة ActionForm أو الحبة المشتقة التي يجب وضع قيمة الحقل فيها أو قراءتها. إذا تم حذف هذه السمة، يتم استخدام النموذج المرتبط بعلامة <html:form>.
الخاصية
اسم الحقل في bean النموذج المرتبط بالحقل المخفي. تأتي القيمة "xxx" المخصصة لحقل HTML السري من تعريف النموذج في ملف التكوين. وقد تم تعريف القيمة الأولية "xxx" هناك للحقل السري.

لفهم العلاقة بين طريقة العرض «formulaire.jsp» و«dynaFormulaire» التي تمثلها في الذاكرة فهماً تاماً، من المهم أن نتذكر أن «dynaFormulaire» تُستخدم في كل من القراءة والكتابة:

يحدث الطلب عندما ينقر المستخدم على زر [إرسال] في النموذج. ثم يقوم المتصفح بـ"إرسال" النموذج HTML إلى الإجراء /confirmation. وقد سبق أن أوضحنا ما يحدث بعد ذلك، وبشكل خاص أن حقول dynaFormulaire ستتلقى قيم الحقول التي تحمل نفس الاسم في النموذج HTML.

ماذا يحدث عندما يطلب وحدة التحكم عرض صفحة formulaire.jsp استجابة لطلب ما؟ دعونا نلقي نظرة فاحصة على العلامات واحدة تلو الأخرى:

العلامة
<body background="<html:rewrite page="/images/standard.jpg"/>">
وظيفة
تقوم بإنشاء كود HTML
<body background="/formulaire2/images/standard.jpg">
العلامة
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
</html:form>
وظيفة
يولد كود HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
العلامة
<html:radio name="dynaFormulaire" property="opt" value="yes">نعم</html:radio>
<html:radio name="dynaFormulaire" property="opt" value="no">لا</html:radio>
وظيفة
إذا كان حقل opt الخاص بـ dynaFormulaire هو "yes"، فقم بإنشاء كود HTML
<input type="radio" name="opt" value="yes" checked="checked">نعم
<input type="radio" name="opt" value="no">لا
علامة
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
<html:checkbox name="dynaForm" property="chk3">3</html:checkbox>
وظيفة
إذا كانت حقول chk1 و chk3 في dynaFormulaire "مفعّلة" وحقل chk2 "غير مفعّل"، فقم بإنشاء كود HTML
<input type="checkbox" name="chk1" value="on" checked="checked">1
<input type="checkbox" name="chk2" value="on">2
<input type="checkbox" name="chk3" value="on" checked="checked">3
علامة
<html:text name="dynaFormulaire" property="inputField" />
وظيفة
إذا تم تعيين حقل الإدخال على "هذا اختبار"، فقم بإنشاء كود HTML
<input type="text" name="inputField" value="هذا اختبار">
العلامة
<html:password name="dynaFormulaire" property="password" />
وظيفة
إذا كان حقل كلمة المرور هو "azerty"، فقم بإنشاء كود HTML
<input type="password" name="password" value="azerty">
العلامة
<html:password name="dynaFormulaire" property="mdp" />
وظيفة
إذا كان حقل "mdp" هو "azerty"، فقم بإنشاء كود HTML
<input type="password" name="password" value="azerty">
العلامة
<html:password name="dynaFormulaire" property="mdp" />
وظيفة
إذا كان حقل "mdp" هو "azerty"، فقم بإنشاء كود HTML
<input type="password" name="password" value="azerty">
العلامة
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="comboValues"/>
</html:select>
وظيفة
إذا كان حقل القائمة المنسدلة هو "combo2"، يقوم بإنشاء كود HTML
<select name="combo">
    <option value="combo0">combo0</option>
    <option value="combo1">combo1</option>
    <option value="combo2" selected="selected">combo2</option>
    <option value="combo3">combo3</option>
    <option value="combo4">combo4</option>
</select>
العلامة
<html:select name="dynaFormulaire" property="simpleList" size="3">
<html:options name="dynaFormulaire" property="simpleListValues"/>
</html:select>
وظيفة
إذا كان حقل simpleList هو "simple1"، يُنشئ كود HTML
<select name="simpleList" size="3">
    <option value="simple0">simple0</option>
    <option value="simple1" selected="selected">simple1</option>
    <option value="simple2">simple2</option>
...
</select>
العلامة
<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
<html:options name="dynaFormulaire" property="multipleListValues"/>
</html:select>
وظيفة
إذا كان حقل listeMultiple عبارة عن المصفوفة {"multiple0", "multiple2"}، يُنشئ كود HTML
<select name="multipleList" multiple="multiple" size="5">
    <option value="multiple0" selected="selected">multiple0</option>
    <option value="multiple1">multiple1</option>
    <option value="multiple2" selected="selected">multiple2</option>
    <option value="multiple3">multiple3</option>
...
</select>
العلامة
<html:hidden name="dynaFormulaire" property="secret"/>
وظيفة
إذا كان الحقل السري يحتوي على القيمة "xxx"، فقم بإنشاء كود HTML
<input type="hidden" name="secret" value="xxx">
العلامة
<html:submit>إرسال</html:submit>
وظيفة
تقوم بإنشاء كود HTML
<input type="submit" value="إرسال">

آخر ما يجب شرحه هو كود JavaScript المضمن في صفحة JSP والمرتبط بزرّي [Clear] اللذين يلغيان تحديد العناصر المحددة في قائمتي simpleList و multipleList:

<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>                                
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>

العلامة

<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">

تولد كود HTML التالي:

<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">

لفهم كود JavaScript المرتبط بأزرار [Clear]، دعونا نستعرض كيفية الإشارة إلى العناصر المختلفة لوثيقة الويب داخل كود JavaScript الذي يستخدم تلك الوثيقة:

البيانات
المعنى
المستند
يشير إلى مستند الويب بأكمله
document.forms
يشير إلى مجموعة النماذج المحددة في المستند
document.forms[i]
يشير إلى النموذج رقم i في المستند
document.forms["formName"]
يشير إلى النموذج <form> الذي تم تعيين سمة الاسم له على "formName"
document.formName
يشير إلى النموذج <form> الذي تساوي سمة الاسم فيه "formName"
document.[form].elements
يشير إلى مجموعة العناصر التي تنتمي إلى النموذج المحدد بواسطة التعبير [form]. تتضمن هذه المجموعة جميع علامات <input> و<textarea> و<select> في النموذج المحدد.
document.[form].elements[i]
يشير إلى العنصر رقم i من [form]
document.[form].elements["componentName"]
يشير إلى العنصر في [form] الذي تساوي سمة الاسم الخاصة به componentName
document.[form]. componentName
يشير إلى العنصر الموجود في [form] الذي تساوي قيمة سمة name فيه componentName
document.[form].[component].value
يشير إلى قيمة مكون [component] في النموذج [form] عندما يحتوي كود HTML الخاص به على سمة value (<input>، <textarea>)
document.[form].[select].selectedIndex
يشير إلى فهرس الخيار المحدد في قائمة. يمكن استخدامه للقراءة والكتابة. يؤدي تعيين هذه الخاصية إلى -1 إلى إلغاء تحديد جميع العناصر في القائمة.
document.[form].[select].options
يشير إلى مصفوفة الخيارات المرتبطة بعلامة <select>
document.[form].[select].options[i]
يشير إلى الخيار رقم i لعلامة <select> المحددة
document.[form].[select].options[i].selected
قيمة منطقية تشير إلى ما إذا كان الخيار رقم i للعنصر [select] المحدد محددًا (صحيح) أم لا. يمكن استخدامها للقراءة والكتابة على حد سواء

دعونا نراجع كود JavaScript الخاص بالزرين:

<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>                                
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>

عند النقر على الزر، يتم تنفيذ الكود المرتبط بسمة "onclick". هنا، يكون الكود مضمنًا. في أغلب الأحيان، نكتب onclick="function(...)"، حيث function هي دالة محددة داخل علامة <script language="javascript">...</script>. ما الذي يفعله الكود أعلاه؟ دعونا نحلل الكود الخاص بالزر الأول:

this
يشير إلى مستند الويب الذي يوجد فيه الزر
this.form
يشير إلى النموذج الذي يوجد فيه الزر
this.form.simpleList
يشير إلى مكون simpleList في النموذج
this.form.simpleList.selectedIndex
يشير إلى مؤشر الخيار المحدد في listeSimple. يؤدي تعيين هذه الخاصية إلى -1 إلى إلغاء تحديد جميع الخيارات.

6.4.2. عرض confirmation.jsp

تذكر أن هذه العرضة يتم عرضها بعد الإجراء /confirmation، أي بعد أن يتم إرسال النموذج الموجود في عرضة formulaire.jsp بواسطة عميل الويب. والغرض الوحيد منها هو عرض القيم التي أدخلها المستخدم. وفيما يلي شفرتها:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
    <head>
      <title>Confirmation</title>
  </head>
  <body background="<html:rewrite page="/images/standard.jpg"/>">
      <h3>Confirmation des valeurs saisies</h3>
    <hr/>
    <table border="1">
        <tr>
        <td>Bouton radio</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="opt"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk1</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk1"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk2</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk2"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk3</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk3"/></td>
      </tr>

        <tr>
        <td>Champ de saisie</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="champSaisie"/></td>
      </tr>
        <tr>
        <td>Mot de passe</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="mdp"/></td>
      </tr>

        <tr>
        <td>Boîte de saisie</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="boiteSaisie"/></td>
      </tr>

        <tr>
        <td>combo</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="combo"/></td>
      </tr>
        <tr>
        <td>liste simple</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="listeSimple"/></td>
      </tr>
            <logic:iterate id="choix" indexId="index" name="dynaFormulaire" property="listeMultiple">
          <tr>
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
        </tr>
            </logic:iterate>
    </table>
        <br>
    <html:link page="/affiche.do">
            Retour au formulaire
        </html:link>    
  </body>
</html>

نقدم هنا مكتبتين جديدتين للعلامات: struts-bean و struts-logic. توفر مكتبة struts-bean إمكانية الوصول إلى الكائنات في سياق الطلب أو الجلسة أو التطبيق. تسمح لك مكتبة struts-logic بتنفيذ منطق التنفيذ باستخدام العلامات. ليست أي من هاتين المكتبتين ضرورية بشكل صارم. كما رأينا، يمكن لصفحة JSP:

  • استرداد الكائنات من الطلب (request.getAttribute(...))، أو الجلسة (session.getAttribute(...))، أو سياق التطبيق
  • تضمين عناصر ديناميكية في كود HTML باستخدام المتغيرات <%= variable %>
  • تحتوي على كود Java <% كود Java %>

إن تضمين كود Java في صفحات JSP يزعج أولئك الذين يفضلون الفصل الصارم بين منطق التطبيق (كود Java) والعرض (استخدام العلامات). ولهذا السبب تم إنشاء مكتبات العلامات من أجلهم.

سنتبع نفس النهج الذي اتبعناه في عرض «formulaire.jsp»، وسنشرح كل علامة موجودة في كود «confirmation.jsp» إذا لم نكن قد تناولناها من قبل في عرض «formulaire.jsp». أولاً، لاحظ أن الصفحة تبدأ بإعلان مكتبات العلامات الثلاث التي ستستخدمها:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

لاحظ أيضًا أنه يجب الإعلان عن هذه المكتبات الثلاث في ملف web.xml الخاص بالتطبيق. سنعلق الآن على العلامات الموجودة في مستند formulaire.jsp:

العلامة
<bean:write name="dynaFormulaire" scope="session" property="opt"/>
تقوم الدالة
كتابة قيمة إلى دفق HTML الحالي. تدعم علامة bean:write السمات التالية:
name: اسم الكائن المراد استخدامه
scope: النطاق (request، session، context) الذي سيتم البحث فيه عن هذا الكائن
property: حقل الكائن المحدد بالاسم الذي سيتم كتابة خاصيته. يمكن أن يكون هذا الحقل كائنًا من أي نوع. سيتم استخدام طريقة toString الخاصة بالكائن.
هنا، يتم كتابة قيمة حقل opt في dynaFormulaire. ستكون النتيجة إما "yes" إذا قام المستخدم بتحديد زر الاختيار الذي يحتوي على السمة value="yes"، أو "no" إذا قام بتحديد زر الاختيار الذي يحتوي على السمة value="no"
العلامة
<bean:write name="dynaFormulaire" scope="session" property="chk1"/>
وظيفة
تقوم بكتابة قيمة حقل chk1 في dynaFormulaire. وستكون النتيجة إما "on" إذا قام المستخدم بتحديد المربع، أو "off" في حالة عدم تحديده. وينطبق الأمر نفسه على chk2 و chk3.
العلامة
<bean:write name="dynaFormulaire" scope="session" property="inputField"/>
وظيفة
تقوم بكتابة قيمة حقل champSaisie في dynaFormulaire، أي النص الذي يكتبه المستخدم في هذا الحقل. وينطبق الأمر نفسه على mdp و boiteSaisie.
العلامة
<bean:write name="dynaFormulaire" scope="session" property="combo"/>
وظيفة
تقوم بكتابة قيمة حقل القائمة المنسدلة في dynaFormulaire. وستكون هذه هي سمة القيمة لعنصر <option> الذي اختاره المستخدم.
العلامة
<bean:write name="dynaFormulaire" scope="session" property="listeSimple"/>
وظيفة
تقوم بكتابة قيمة حقل simpleList في dynaForm. وستحتوي على سمة value لعنصر <option> الذي اختاره المستخدم، في حال تم اختيار عنصر ما. وإلا، فستكون سلسلة فارغة.
العلامة
            <logic:iterate id="choice" indexId="index" name="dynaForm" property="multipleList">
          <tr>
          <td>قائمة متعددة[<bean:write name="index"/>]</td>
          <td><bean:write name="choice"/></td>
        </tr>
            </logic:iterate>
وظيفة
هنا، نقدم علامات المنطق. نحن نتعامل مع قائمة متعددة الخيارات. قيمة حقل listeMultiple الخاص بكائن dynaFormulaire هي مصفوفة من سلاسل الأحرف. في Java، كنا سنكتب حلقة. تسمح لنا علامة logic:iterate بتنفيذ هذه الحلقة نفسها دون كتابة كود Java. في هذا المثال، تحتوي علامة logic:iterate على السمات التالية:
name="dynaFormulaire": اسم الكائن المراد استخدامه
property="listeMultiple": اسم الخاصية في الكائن المحدد بالاسم الذي يحتوي على المجموعة المراد تكرارها في الحلقة. هنا، هذه المجموعة هي مصفوفة القيم المحددة في listeMultiple. قد تكون هذه المصفوفة فارغة.
id="choix": معرف يشير إلى العنصر الحالي للمصفوفة في كل تكرار. خلال التكرار الأول، سيمثل choix listeMultiple[0]، وخلال التكرار الثاني سيمثل listeMultiple[1]، وهكذا دواليك.
indexID="index": معرف يشير إلى فهرس عنصر المصفوفة الحالي في كل تكرار للحلقة. خلال التكرار الأول، سيكون لـ index القيمة 0؛ وخلال التكرار الثاني، القيمة 1؛ وهكذا دواليك.
يتم تكرار كود HTML الموجود بين العلامتين <logic:iterate ...> و</logic:iterate> لكل عنصر في المجموعة المحددة بواسطة الزوج (name,property). الجزء الديناميكي من هذا الكود هو كما يلي:
          <td>multiple list[<bean:write name="index"/>]</td>
          <td><bean:write name="choice"/></td>
بناءً على ما قيل سابقًا، في التكرار رقم i (i>=0)، يكون كود HTML الذي تم إنشاؤه مكافئًا لما يلي:
          <td>قائمة متعددة[<%=i%>]</td>
          <td><%=multipleList[i]%></td>
علامة
    <html:link page="/affiche.do">
            العودة إلى النموذج
        </html:link>
وظيفة
رابطًا نسبيًا لسياق التطبيق، مما يلغي الحاجة إلى معرفة السياق. رمز HTML الذي تولده هذه العلامة هو كما يلي:
<a href="/formulaire2/affiche.do">العودة إلى النموذج</a>

6.5. فئات Java

يشير ملف التكوين struts-config.xml إلى فئتين من فئات Java:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >

فئة DynaFormulaire هي الفئة التي ستحتوي على القيم من العرض رقم 1، formulaire.jsp. فئة InitFormulaireAction هي الفئة التي ستعالج قيم النموذج المرسلة عبر زر [Submit] في formulaire.jsp.

6.5.1. فئة DynaFormulaire

للاحتفاظ بقيم النموذج، يكفي وجود كائن من نوع DynaActionForm ما لم تكن بحاجة إلى تجاوز إحدى طرق إعادة الضبط أو التحقق من صحة هذه الفئة. هنا، لا يلزم تجاوز طريقة validate نظرًا لعدم إجراء أي تحقق من صحة البيانات. ومع ذلك، يلزم تجاوز طريقة reset. ويرجع ذلك إلى أن حقول كائن DynaFormulaire ستتلقى قيمها من النموذج المرسَل بواسطة عميل الويب. ومع ذلك، قد لا تتلقى بعض الحقول قيمة إذا لم تكن موجودة في الطلب. ويحدث هذا في الحالات التالية:

  • مربع اختيار لم يتم تحديده من قبل المستخدم
  • قائمة تحتوي على أكثر من خيار واحد ولم يتم تحديد أي منها

بالنسبة للنماذج التي تحتوي على هذا النوع من المكونات، يجب أن

  • تعيين القيمة "off" للحقل المرتبط بمربع الاختيار
  • تعيين السلسلة الفارغة للحقل المرتبط بقائمة الاختيار الفردي
  • تعيين مصفوفة فارغة من السلاسل إلى الحقل المرتبط بقائمة الاختيار المتعدد

وبالتالي، إذا لم تتلقى هذه الحقول قيمة من الاستعلام، فإنها تحتفظ بالقيمة التي تم تعيينها بواسطة إعادة الضبط، والتي تتوافق مع حالة المكون في النموذج الذي تم التحقق من صحته من قبل المستخدم (مربع الاختيار غير محدد، قائمة بدون عناصر محددة).

فيما يلي كود فئة DynaFormulaire، وهي فئة فرعية من DynaActionForm:

package istia.st.struts.formulaire;

import org.apache.struts.action.DynaActionForm;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;

public class DynaFormulaire extends DynaActionForm {
  public void reset(ActionMapping mapping, HttpServletRequest request){
    // reset checkboxes - value off
    set("chk1","off");
    set("chk2","off");
    set("chk2","off");
    // reset listeSimple - empty string
    set("listeSimple","");
     // reset listeMultiple - empty table
    set("listeMultiple",new String[]{});
  }
}

6.5.2. فئة InitFormAction

ترتبط فئة InitFormAction بالإجراء /init في ملف struts-config.xml:

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

يتم استخدام الإجراء /init مرة واحدة فقط أثناء الإنشاء الأولي لكائن DynaForm. والغرض منه هو توفير محتوى لقوائم الاختيار الثلاث الخاصة بالنموذج: simpleList و multipleList و dropdownList. ويتم توفير هذا المحتوى في شكل ثلاثة مصفوفات، وهي خصائص لكائن dynaForm:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
...
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                                          
        </form-bean>            

بمجرد تهيئة المصفوفات valuesCombo و valuesSingleList و valuesMultipleList بواسطة InitFormAction، لن تكون هناك حاجة إلى تهيئتها مرة أخرى. ويرجع ذلك إلى أن كائن dynaForm يتم وضعه في الجلسة، وبالتالي يحتفظ بقيمته عبر دورات الطلب والاستجابة. ولهذا السبب يتم تنفيذ الإجراء /init مرة واحدة فقط. وفيما يلي كود InitFormAction:

package istia.st.struts.formulaire;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;

public class InitFormulaireAction
  extends Action {
  public ActionForward execute(ActionMapping mapping, ActionForm form,
       HttpServletRequest request, HttpServletResponse response) throws IOException,    ServletException {

     // prepares the form to be displayed

     // we put the information needed for the form in its bean
    DynaFormulaire formulaire = (DynaFormulaire) form;
    formulaire.set("valeursCombo", getValeurs(5, "combo"));
    formulaire.set("valeursListeSimple", getValeurs(7, "simple"));
    formulaire.set("valeursListeMultiple", getValeurs(10, "multiple"));
     // we give back
    return mapping.findForward("afficherFormulaire");
  } //execute

   // list of combo values
  private String[] getValeurs(int taille, String label) {
    String[] valeurs = new String[taille];
    for (int i = 0; i < taille; i++) {
      valeurs[i] = label + i;
    }
    return valeurs;
  }
}
  • تُوسّع هذه الفئة فئة Action. وهذا أمر إلزامي.
  • يستخدم وحدة التحكم Struts كائن Action عبر طريقة execute الخاصة به. ولذلك، فإن هذه هي الطريقة التي يجب إعادة تعريفها. تتلقى هذه الطريقة المعلمات التالية:
    • ActionMapping mapping: كائن يمثل تكوين التطبيق في struts-config.xml
    • ActionForm form: النموذج المرتبط بالإجراء، إذا تم تعريفه في تكوين الإجراء (سمة اسم الإجراء).
    • HttpServletRequest request: طلب العميل
    • HttpServletResponse: الاستجابة للعميل
  • يجب أن تقوم فئة InitFormulaireAction بتهيئة النموذج dynaFormulaire. يتم تمرير هذا إلى طريقة execute كمعلمة النموذج ActionForm. تذكر أن dynaFormulaire من النوع DynaFormulaire، وهي فئة مشتقة من فئة DynaActionForm، والتي هي نفسها مشتقة من فئة ActionForm.
  • في طريقة execute، يتم تعيين القيم إلى الحقول الثلاثة valeursCombo و valeursListeSimple و valeursListeMultiple باستخدام طريقة set لفئة DynaActionForm. هذه القيم هي مصفوفات عشوائية من أجل التبسيط. لاحظ أن طريقة set تعين قيمة لحقل موجود. ولا يمكن استخدامها لإنشاء حقول جديدة. ولهذا السبب من الضروري تعريف الحقول الثلاثة valeursCombo و valeursListeSimple و valeursListeMultiple في تعريف كائن dynaFormulaire في struts-config.xml.
  • تنتهي طريقة execute بإرجاع مفتاح العرض المراد عرضه إلى وحدة التحكم كاستجابة للعميل. هنا، هو مفتاح afficherFormulaire، الذي تم ربطه في ملف struts-config.xml بعرض /vues/formulaire.jsp.

6.6. النشر

هيكل دليل التطبيق كما يلي:

  

Image

Image

يرجى ملاحظة أن ملف ApplicationResources.properties المذكور أعلاه مطلوب من قِبل مكتبة العلامات struts-bean. ونحن نعلم أن هذا الملف يحتوي على رسائل التطبيق. ويمكن لمكتبة struts-bean الوصول إلى هذه الرسائل. وفي هذه الحالة، لا يحدد تطبيقنا أي رسائل. ولذلك، فإن ملف ApplicationResources.properties موجود ولكنه فارغ.

6.7. الخلاصة

في هذا الدرس، قمنا بتفصيل كيفية إدارة المكونات المختلفة لنموذج HTML. يمكننا الآن استخدام نماذج معقدة في تطبيقات Struts الخاصة بنا.