4. استخدام النماذج الديناميكية
4.1. إعلان النموذج الديناميكي
لقد رأينا أن Struts يستخدم كائنات ActionForm لتخزين قيم نماذج HTML التي تعالجها مختلف سيرفلتات التطبيق. لكل نموذج في تطبيقنا، نحتاج إلى إنشاء فئة مشتقة من ActionForm. قد يصبح هذا الأمر مرهقًا بسرعة نظرًا لأنه لكل حقل xx، يجب أن نكتب طريقتين: setXx و getXx. يوفر Struts خيار استخدام نماذج
- التي يتم إعلان هيكلها في ملف struts-config.xml داخل قسم <form-beans>
- ، والتي يتم إنشاؤها ديناميكيًا بواسطة بيئة Struts وفقًا للهيكل المعلن
وبالتالي، يمكن تعريف الفئة المستخدمة لتخزين قيم الاسم والعمر في تطبيق strutspersonne على النحو التالي:
<form-beans>
<form-bean name="frmPersonne" type="org.apache.struts.actions.DynaActionForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
لكل حقل في النموذج، نحدد علامة <form-property> بسمتين:
- name: اسم الحقل
- type: نوعه في Java
نظرًا لأن قيم النموذج المرسلة بواسطة عميل الويب هي سلاسل نصية، فإن الأنواع الأكثر استخدامًا هي java.lang.String للحقول ذات القيمة الواحدة و java.lang.String[] للحقول متعددة القيم (مربعات الاختيار التي تحمل الاسم نفسه، وقوائم الاختيار المتعدد، وما إلى ذلك). تحتوي فئة DynactionForm، مثل فئة ActionForm، على طريقة validate لا تقوم بأي شيء. لكي تتحقق من صحة معلمات النموذج، يجب عليك توسيعها وكتابة طريقة validate بنفسك. وبالتالي، سيكون إعلان النموذج كما يلي:
<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>
سنحتاج إلى كتابة فئة istia.st.struts.personne.PersonneDynaForm بأنفسنا.
4.2. كتابة فئة DynaActionForm المرتبطة بالنموذج الديناميكي
في الأعلى، قمنا بربط الفئة istia.st.struts.personne.PersonneDynaForm بالنموذج (name, age). سنقوم الآن بكتابة هذه الفئة:
package istia.st.struts.personne;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class PersonneDynaForm extends DynaActionForm {
// validation
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
// error management
ActionErrors erreurs = new ActionErrors();
// name must be non-empty
String nom = (String)this.get("nom");
if (nom == null || nom.trim().equals("")) {
erreurs.add("nomvide", new ActionError("personne.formulaire.nom.vide"));
}
// age must be non-empty
String age = (String)this.get("age");
if (age == null || age.trim().equals("")) {
erreurs.add("agevide", new ActionError("personne.formulaire.age.vide"));
}
else {
// age must be a positive integer
if (!age.matches("^\\s*\\d+\\s*$")) {
erreurs.add("ageincorrect", new ActionError("personne.formulaire.age.incorrect", age));
// return the list of errors
}
} //if
// return the error list
return erreurs;
}
}//class
يجب ملاحظة النقاط التالية:
- تستمد الفئة من DynaActionForm
- تمت إعادة كتابة طريقة validate الخاصة بفئة DynaActionForm. عند تنفيذها بواسطة وحدة التحكم Struts، يتم إنشاء كائن PersonneDynaForm. يحتوي هذا الكائن على قاموس تكون مفاتيحه هي حقول النموذج name و age، وقيمه هي قيم تلك الحقول. للوصول إلى حقل داخل طرق DynaActionForm، استخدم طريقة Object get(String fieldName). لتعيين قيمة لحقل ما، استخدم طريقة void set(String fieldName, Object value). راجع تعريف فئة DynaActionForm للحصول على وصف كامل.
- بمجرد استرداد قيم حقول الاسم والعمر في النموذج، لا تختلف طريقة validate عن تلك التي تمت كتابتها عندما تم ربط النموذج بكائن ActionForm.
4.3. فئة FormAction الجديدة
يحدد ملف التكوين الإجراء /main التالي:
...
<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>
....
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
type="istia.st.struts.personne.FormulaireAction"
>
<forward name="reponse" path="/reponse.do"/>
</action>
هذا التعريف هو نفسه الموجود في تطبيق strutspersonne. يتم تنفيذ الإجراء /main بواسطة كائن من نوع FormulaireAction. كان هذا الكائن يستقبل القيم من نموذج frmPersonne في كائن من نوع FormulaireBean. والآن يستقبلها في كائن من نوع PersonneDynaForm. لذلك، يجب إعادة كتابة الفئة:
package istia.st.struts.personne;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import javax.servlet.ServletException;
import istia.st.struts.personne.PersonneDynaForm;
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
PersonneDynaForm formulaire=(PersonneDynaForm)form;
request.setAttribute("nom",formulaire.get("nom"));
request.setAttribute("age",formulaire.get("age"));
return mapping.findForward("reponse");
}//execute
}
يجب ملاحظة النقاط التالية:
- يجب استيراد فئة PersonneDynaForm، التي تحتوي على بيانات النموذج، للوصول إلى تعريفها
- تسترد طريقة execute قيم معلمات النموذج باستخدام طريقة [DynaActionForm].get.
بالمقارنة مع فئة FormAction في تطبيق strutspersonne، لم يتغير سوى طريقة الوصول إلى قيم النموذج.
4.4. نشر واختبار تطبيق strutspersonne1
4.4.1. إنشاء السياق
لقد أطلقنا على هذا التطبيق الجديد اسم strutspersonne1. نقوم بإنشاء تعريف جديد في ملف <tomcat>\conf\serveur.xml لـ Tomcat 4.x:
بمجرد الانتهاء من ذلك، يجب إعادة تشغيل Tomcat. يمكنك التحقق من صحة السياق عن طريق طلب عنوان URL:
http://localhost:8080/strutspersonne1/

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

4.4.3. تجميع الفئات
لدينا فئتان يجب إنشاؤهما: PersonneDynaForm و FormulaireAction، حيث تستخدم الأخيرة الأولى. يمكننا إنشاؤهما وتجميعهما باستخدام مشروع JBuilder:

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

يصبح ملف التكوين 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="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>
<action-mappings>
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
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"/>
</struts-config>
هذا الملف مطابق لملف تطبيق strutspersonne، باستثناء تعريف النموذج الديناميكي (القسم المحدد بإطار).
في المجلد WEB-INF/classes، ضع الفئات التي تم تجميعها بواسطة JBuilder:

في المجلد WEB-INF\classes\resources، ضع ملف الرسائل. لم يتغير.
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 [{0}] est incorrect</li>
errors.header=<ul>
errors.footer=</ul>

4.5. الاختبارات
نحن جاهزون للاختبار. فيما يلي بعض لقطات الشاشة التي ندعو القارئ إلى إعادة إنتاجها.
اطلب عنوان URL http://localhost:8080/strutspersonne1/formulaire.do:

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

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

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

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

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

4.6. الخلاصة
يسهل استخدام النماذج الديناميكية كتابة فئات ActionForm المسؤولة عن تخزين قيم النموذج. يمكننا المضي قدماً في إدارة النماذج. في تطبيق strutspersonne1، أنشأنا فئة PersonneDynaForm للتحقق من صحة قيم النموذج (الاسم، العمر). في الممارسة العملية، تحدث بعض عمليات التحقق من الصحة بشكل متكرر: حقل غير فارغ، حقل يتحقق من صحة تعبير عادي محدد، حقل عدد صحيح، حقل تاريخ، إلخ. يمكن بعد ذلك تحديد هذا النوع من التحقق من الصحة القياسي في ملف التكوين struts-config.html. إذا كانت جميع عمليات التحقق من الصحة المطلوب إجراؤها "قياسية"، فلا داعي لكتابة فئة للنموذج. وهذا ما سنقوم بفحصه الآن.