3. معالجة النموذج بواسطة وحدة التحكم
ننتقل الآن إلى معالجة قيم النموذج بواسطة وحدة التحكم عندما يضغط المستخدم على الزر [Envoyer] في النموذج.
3.1. الملف struts-config.xml
يصبح ملف التكوين الجديد struts-config.xml لوحدة التحكم Struts كما يلي:
<?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.FormulaireBean"
/>
</form-beans>
<action-mappings>
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
parameter="/vues/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
<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>
لقد أبرزنا التغييرات:
- يظهر قسم <form-beans>. ويُستخدم هذا القسم لتعريف الفئات المرتبطة بكل نموذج من نماذج التطبيق. يجب أن يكون عدد علامات <form-bean> مساوياً لعدد النماذج المختلفة في التطبيق. هنا، لدينا نموذج واحد فقط، لذا يوجد قسم <form-bean> واحد فقط. لكل نموذج، يجب أن نحدد:
- اسمه (السمة name)
- اسم الفئة المشتقة من ActionForm والمسؤولة عن تخزين قيم النموذج (السمة type)
لا يمكن أن تكون هاتان السمتان عشوائيتين. بل يجب أن تكونا مطابقتين لتلك المستخدمة في علامة <html:form> في كود النموذج HTML. وللتذكير، إليك كود النموذج (الاسم، العمر):
يجب الإعلان عن النموذج بنفس الطريقة في الملف struts-config.html. وهذا ما تم القيام به هنا:
- تم تغيير تكوين الإجراء /main. هذا الإجراء مسؤول عن معالجة قيم النموذج. لذا يجب تزويده بالمعلومات التي يحتاجها في النموذج:
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
parameter="/vues/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
ستقوم خدمة /main بمعالجة نموذج يجب تسميته. ويقوم السمة name بهذه المهمة. يجب أن يشير هذا الاسم إلى السمة name لأحد أقسام <form-bean>، وهو هنا frmPersonne.
تشير السمة scope="session" إلى أنه يجب تخزين قيم النموذج في الجلسة. وهذا ليس ضروريًا دائمًا. لكنه ضروري هنا. ففي الواقع، نجد في العرضين /reponse.do و/erreurs.do روابط تعيدنا إلى النموذج. في كلتا الحالتين، نريد عرض النموذج مع القيم التي أدخلها المستخدم خلال تبادل سابق بين العميل والخادم. ومن هنا تأتي ضرورة تخزين النموذج في الجلسة.
تشير السمة validate إلى ما إذا كان يجب استدعاء الطريقة validate الخاصة بالكائن frmPersonne أم لا. تُستخدم هذه الطريقة للتحقق من صحة بيانات النموذج. هنا، نشير إلى أنه يجب التحقق من البيانات، مما يعني أنه سيتعين علينا كتابة طريقة validate في الفئة FormulaireBean. يتم استدعاء طريقة validate الخاصة بالنموذج بواسطة وحدة التحكم Struts قبل استدعاء السيرفلت /main. وتُرجع هذه الطريقة كنتيجة كائنًا من النوع ActionErrors يشبه قائمة الأخطاء. إذا كانت هذه القائمة موجودة وغير فارغة، فستتوقف وحدة التحكم Struts عند هذا الحد وسترسل كاستجابة العرض المشار إليه بواسطة السمة input. ستتلقى طريقة العرض في الطلب قائمة ActionErrors التي يمكنها عرضها باستخدام العلامة <html:errors>. في المثال أعلاه، نحدد أنه في حالة وجود أخطاء، يجب على السيرفلت /main إرسال طريقة العرض /erreurs.do. تجدر الإشارة إلى أن هذه العرض مرتبطة بالعرض التالي: URL /vues/erreurs.reponse.jsp:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<html:errors/>
<html:link page="/formulaire.do">
Retour au formulaire
</html:link>
</body>
</html>
تستخدم طريقة العرض علامة <html:errors> بشكل صحيح، والتي ستسمح بعرض قائمة الأخطاء. في قائمة الأخطاء هذه، لا نجد رسائل الأخطاء بل معرّفات الرسائل الموجودة في الملف المشار إليه بواسطة علامة <message-resources> (ملاحظة: resources بحرف s واحد):
تشير العلامة أدناه إلى أن الملف الذي يحتوي على الرسائل المستخدمة من قبل التطبيق موجود في الملف WEB-INF/classes/ressources/personneressources.properties:

ماذا يوجد في هذا الملف؟ إنه ملف خصائص يتوافق مع فئة Properties في Java، أي مجموعة من الأسطر التي تتكون من مفتاح=قيمة:
errors.header=<ul>
errors.footer=</ul>
personne.formulaire.nom.vide=<li>Vous devez indiquer un nom</li>
personne.formulaire.age.incorrect=<li>L'âge [{0}] est incorrect</li>
لهذا الملف الخاص بالرسائل وظيفتان على الأقل:
- يسمح بتغيير رسائل التطبيق دون الحاجة إلى إعادة تجميعه
- يتيح تدويل تطبيقات Struts. يمكن بالفعل إنشاء عدة ملفات موارد، ملف لكل لغة. سيستخدم Struts تلقائيًا ملف الرسائل الصحيح شريطة الالتزام بمعايير معينة في تسمية هذه الملفات.
- إذا عادت طريقة validate الخاصة بالنموذج بقائمة أخطاء فارغة، فإن وحدة التحكم Struts تستدعي طريقة execute الخاصة بالسيرفلت ForwardAction. من المهم أن نفهم هنا أنه عندما يتم تنفيذ طريقة execute الخاصة بالسيرفلت، فهذا يعني أن بيانات النموذج قد اعتُبرت صالحة (بشرط أن تكون قد تم التحقق منها بواسطة validate="true"). وفي طريقة execute الخاصة بالسيرفلت المرتبطة بالإجراء، يقوم المطور بمعالجة النموذج فعليًّا. وهنا يكمن جوهر المعالجة (منطق التطبيق، واستخدام فئات الأعمال وفئات الوصول إلى البيانات). وفي النهاية، تُرجع الطريقة نتيجة من النوع ActionForward تُشير إلى المُنشئ بالعرض الذي يجب إرساله كاستجابة إلى العميل. هنا استخدمنا الإجراء المُعرَّف مسبقًا ForwardAction من Struts. وتكتفي طريقة execute الخاصة به بإرجاع ActionForward يشير إلى URL المحدد بواسطة السمة parameter:
<action
path="/main"
name="frmPersonne"
validate="true"
input="/erreurs.do"
parameter="/vues/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
لذا، إذا كانت بيانات النموذج صالحة، فستقوم الإجراء /main بإرجاع العرض /vues/main.html الذي استخدمناه سابقًا.
3.2. الفئة الجديدة FormulaireBean
لقد أنشأنا بالفعل نسخة أولية من الفئة FormulaireBean المكلفة بتخزين بيانات (الاسم، العمر) النموذج formulaire.personne.jsp. لم تكن هذه النسخة تتحقق من صحة البيانات. والآن، يتعين علينا القيام بذلك لأننا أشرنا في الملف struts-config.xml إلى ضرورة التحقق من صحة بيانات النموذج (validate="true") قبل إرسالها إلى السيرفلت ForwardAction. يصبح كود الفئة كما يلي:
package istia.st.struts.personne;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class FormulaireBean
extends ActionForm {
// الاسم
private String nom = null;
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
// العمر
private String age = null;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
// التحقق من الصحة
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
// إدارة الأخطاء
ActionErrors erreurs = new ActionErrors();
// يجب ألا يكون الاسم فارغًا
if (nom == null || nom.trim().equals("")) {
erreurs.add("nomvide", new ActionError("personne.formulaire.nom.vide"));
// يجب أن يكون العمر عددًا صحيحًا موجبًا
}
if (age == null || age.trim().equals("")) {
erreurs.add("agevide", new ActionError("personne.formulaire.age.vide"));
}
else {
// يجب أن يكون العمر عددًا صحيحًا موجبًا
if (!age.matches("^\\s*\\d+\\s*$")) {
erreurs.add("ageincorrect", new ActionError("personne.formulaire.age.incorrect", age));
// يتم عرض قائمة الأخطاء
}
} //إذا
// يتم عرض قائمة الأخطاء
return erreurs;
}
}
يكمن الجديد في كتابة طريقة validate. يتم استدعاء هذه الطريقة من قبل وحدة التحكم Struts بعد أن تقوم هذه الأخيرة بتعيين قيم حقول النموذج التي تحمل نفس الاسم في السمتين «الاسم» و«العمر» للفئة. ويجب أن تتحقق هذه الطريقة من صحة السمتين «الاسم» و«العمر». الكود أعلاه سهل الفهم إلى حد ما:
- يتم إنشاء قائمة أخطاء (ActionErrors أخطاء) فارغة
- يتم التحقق من الحقل «الاسم». إذا كان فارغًا، تُضاف خطأ إلى قائمة الأخطاء باستخدام الطريقة ActionErrors.add("المفتاح", ActionError).
- ويتم إجراء الأمر نفسه إذا لم يكن حقل «العمر» عددًا صحيحًا.
- تقوم الطريقة validate بإرجاع قائمة الأخطاء (ActionErrors أخطاء) إلى وحدة التحكم Struts. إذا كانت أخطاء تساوي null أو إذا كانت erreurs.size() تساوي 0، تعتبر وحدة التحكم أنه لم تحدث أخطاء. وعندئذٍ سيقوم بتنفيذ الطريقة execute للفئة Action المرتبطة بالإجراء (type="org.apache.struts.actions.ForwardAction"). وإلا، فسيعيد عرض الصفحة المرتبطة بحالة وجود أخطاء في النموذج (input="/erreurs.do").
نضيف خطأً إلى قائمة الأخطاء ActionErrors عن طريق ActionErrors.add("cléErreur", new ActionError("cléMessage"[,param0, param1, param2, param3])). يُستخدم المعامل الأول "cléErreur" لتعيين عنصر ActionError بشكل فريد في القائمة ActionErrors، تمامًا كما هو الحال في القاموس. ويمكن أن يكون أي قيمة. ActionError هو كائن يتم ربطه برسالة خطأ باستخدام مُنشئه ActionError(String cléMessage[,String param0, String param1, String param2, String param3]) حيث يمثل cléMessage معرّف الرسالة المرتبطة بالخطأ، ويمكن أن يتضمن ما يصل إلى 4 معلمات اختيارية. المعرف cléMessage ليس معرفًا عاديًا. إنه أحد المعرفات الموجودة في الملف المشار إليه بعلامة <message-resources> في الملف struts-config.xml:
تجدر الإشارة إلى أن هذا الملف (في الواقع WEB-INF/classes/ressources/personneressources.properties) يحتوي على المفاتيح التالية:
errors.header=<ul>
errors.footer=</ul>
personne.formulaire.nom.vide=<li>Vous devez indiquer un nom</li>
personne.formulaire.age.incorrect=<li>L'âge [{0}] est incorrect</li>
يمكن التحقق من أن مفاتيح الرسائل المستخدمة بواسطة طريقة validate للفئة FormulaireBean موجودة بالفعل في الملف أعلاه. وقد استخدمنا العلامة HTML <li> لكل رسالة خطأ حتى تعرضها العلامة <html:errors> كقائمة HTML. وقد رأينا أن الكائن ActionError يمكن إنشاؤه ليس فقط باستخدام مفتاح رسالة، بل أيضًا باستخدام معلمات إضافية:
إذا تم إنشاء كائن ActionError باستخدام معلمات إضافية (بحد أقصى أربعة)، فيمكن الوصول إلى هذه المعلمات في نص الرسالة عبر الترميز من {0} إلى {3}. وبالتالي، فإن طريقة validate الخاصة بـ FormulaireBean تُنشئ ActionError باستخدام المفتاح personne.formulaire.age.incorrect والمعلمة الإضافية param0 age:
الرسالة المرتبطة، في ملف .properties الخاص بالرسائل، بالمفتاح personne.formulaire.age.incorrect هي
سيتم استبدال {0} بقيمة العمر. وأخيرًا، سيتم كتابة الرسائل التي تحتوي على المفاتيح errors.header و errors.footer قبل قائمة الأخطاء وبعدها على التوالي. وهنا، ستُستخدم هاتان المفتاحتان لإدراج العلامات HTML <ul> و </ul> التي يجب أن تحيط بالعلامات <li>.
3.3. اختبارات صحة النموذج
نحن جاهزون الآن لإجراء اختبارات صحة النموذج. نذكر أدناه الأماكن التي يجب وضع مكونات التطبيق المختلفة فيها:
![]() | |
![]() | |
![]() | |
![]() |
3.3.1. اختبار 1
لنُعيد تشغيل Tomcat حتى يقرأ ملفات التكوين الجديدة، ثم نطلبhttp://localhost:8080/strutspersonne/formulaire.do:

التفسيرات:
- في struts-config.html، تم استغلال القسم التالي:
<action
path="/formulaire"
parameter="/vues/formulaire.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
إذا قمنا بعرض الرمز HTML للصفحة المستلمة، نلاحظ أن علامة <form> للصفحة هي كما يلي:
وبالتالي، فإن الزر [Envoyer]، وهو من نوع «إرسال» (submit)، سيرسل بيانات النموذج إلى URL /strutspersonne/main.do.
3.3.2. الاختبار 2
لنستخدم الزر [Envoyer] مع ترك حقول الإدخال فارغة. نحصل على الرد التالي:

التفسيرات:
- كما هو موضح أعلاه، تم إرسال بيانات النموذج إلى URL /strutspersonne/main.do. ثم تم استخدام الأقسام التالية من الملف struts-config.xml:
<form-bean
name="frmPersonne"
type="istia.st.struts.personne.FormulaireBean"
scope="session"
/>
....
<action
path="/main"
name="frmPersonne"
validate="true"
input="/erreurs.do"
parameter="/vues/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
تم تشغيل الإجراء /main. ويستخدم هذا الإجراء النموذج frmPersonne (name="frmPersonne"). وبالتالي، قام وحدة التحكم Struts بإنشاء مثيل، عند الضرورة، لكائن من الفئة FormulaireBean (type="istia.st.struts.personne.FormulaireBean" في علامة form-bean). وقام بملء السمتين «name» و«age» لهذا الكائن بقيم الحقول التي تحمل نفس الاسم في النموذج HTML:
<table>
<tr>
<td>Nom</td>
<td><html:text property="nom" size="20"/></td>
</tr>
<tr>
<td>Age</td>
<td><html:text property="age" size="3"/></td>
</tr>
<tr>
</table>
وبعد ذلك، قام مُراقب Struts باستدعاء الطريقة validate الخاصة بالكائن FormulaireBean لأن السمة validate الخاصة بالإجراء /main تم تعيينها على القيمة true في ملف التكوين:
<action
path="/main"
name="frmPersonne"
validate="true"
input="/erreurs.do"
parameter="/vues/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
طريقة validate الخاصة بالفئة FormulaireBean هي كما يلي:
// التحقق من الصحة
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
// معالجة الأخطاء
ActionErrors erreurs = new ActionErrors();
// يجب ألا يكون الاسم فارغًا
if (nom == null || nom.trim().equals("")) {
erreurs.add("nomvide", new ActionError("personne.formulaire.nom.vide"));
// يجب أن يكون العمر عددًا صحيحًا موجبًا
}
if (age == null || age.trim().equals("")) {
erreurs.add("agevide", new ActionError("personne.formulaire.age.vide"));
}
else {
// يجب أن يكون العمر عددًا صحيحًا موجبًا
if (!age.matches("^\\s*\\d+\\s*$")) {
erreurs.add("ageincorrect", new ActionError("personne.formulaire.age.incorrect", age));
// يتم عرض قائمة الأخطاء
}
} //إذا
// يتم عرض قائمة الأخطاء
return erreurs;
}
نظرًا لأن الحقلين [nom] و [age] كانا فارغين، فقد أنشأت طريقة validate المذكورة أعلاه قائمة من خطأين وأرسلتها إلى وحدة التحكم Struts. ونظرًا لوجود أخطاء، قامت وحدة التحكم بعد ذلك بإرجاع العرض المرتبط بالسمة input إلى العميل. ولمعرفة ماهية هذه العرض، استخدم القسم التالي من ملف التكوين الخاص به:
<action
path="/erreurs"
parameter="/vues/erreurs.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
وبالتالي، فقد أرسل في النهاية الصفحة /vues/erreurs.personne.jsp. وتحتوي هذه الصفحة على الكود التالي:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<html:errors/>
<html:link page="/formulaire.do">
Retour au formulaire
</html:link>
</body>
</html>
تقوم العلامة <html:errors> بعرض قائمة الرسائل التي أرسلها إليها وحدة التحكم Struts. وهي تستخدم ملف الرسائل المشار إليه بواسطة العلامة <message-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>
- يتم كتابة الرسالة المرتبطة بالمفتاح errors.header
- يتم كتابة الرسائل المرتبطة بالمفاتيح المختلفة في القائمة ActionErrors التي تم استلامها
- يتم كتابة الرسالة المرتبطة بالمفتاح errors.footer
3.3.3. الاختبار 3
لنستخدم الرابط [Retour au formulaire] الموجود في صفحة الأخطاء. نحصل على الصفحة التالية:

التفسيرات:
- يحتوي الرابط [Retour au formulaire] على الرمز HTML التالي:
استخدمت وحدة التحكم Struts القسم التالي من ملف التكوين الخاص بها:
<action
path="/formulaire"
parameter="/vues/formulaire.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
وبالتالي، فقد أعاد عرض /vues/formulaire.personne.jsp.
3.3.4. الاختبار 4
نقوم بملء النموذج التالي ثم نستخدم الزر [Envoyer]:

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

التفسيرات: هي نفسها كما في الاختبار رقم 2.
3.3.5. الاختبار 5
نستخدم الرابط [Retour au formulaire] المذكور أعلاه. نحصل على الصفحة التالية:

نلاحظ أن النموذج يظهر بالصيغة التي قمنا بتأكيدها.
التفسيرات: هي نفس تفسيرات الاختبار رقم 3 مع معلومة إضافية:
- يحتوي النموذج المعروض HTML على العلامات التالية:
<table>
<tr>
<td>Nom</td>
<td><html:text property="nom" size="20"/></td>
</tr>
<tr>
<td>Age</td>
<td><html:text property="age" size="3"/></td>
</tr>
<tr>
</table>
تؤدي علامات <html:text> وظيفتين:
- عند إرسال قيم النموذج من العميل إلى الخادم، تُعيَّن قيم حقول الإدخال في النموذج إلى الحقول التي تحمل نفس الاسم في الكائن FormulaireBean
- عند إرسال الخادم إلى العميل رمز HTML الخاص بالنموذج المراد عرضه، يتم تهيئة سمات value لحقول الإدخال المرتبطة بعلامات <html:text> بقيم الحقول التي تحمل نفس الاسم في الكائن FormulaireBean.
نحن هنا أمام عمليتي تبادل مختلفتين بين العميل والخادم:
- في الأول، قام المستخدم بملء النموذج وإرساله إلى الخادم
- في العملية الثانية، استخدم المستخدم الرابط [Retour au formulaire] للعودة إلى النموذج.
الطريقة الوحيدة لإعادة عرض النموذج بقيمه الأصلية في التفاعل الثاني هي تخزين هذه القيم في جلسة عمل العميل. وهذا ما تم طلبه في القسم الذي يهيئ الإجراء /main:
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
parameter="/vues/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
لو كنا قد استخدمنا scope="request"، لما تم تخزين بيانات النموذج في الجلسة، ولما تمكنا من استرجاع قيمها في التبادل الثاني.
3.3.6. الاختبار 6
لنعد إلى النموذج لإدخال بيانات صالحة هذه المرة:

لنضغط على زر إرسال النموذج. نحصل على النتيجة التالية:

التفسيرات:
- نظرًا لأن الزر [Envoyer] يرسل قيم النموذج إلى URL /strutspersonne/main.do، فإننا نجد نفس التفسيرات الموجودة في الاختبار رقم 2 حتى العودة إلى وحدة التحكم Struts بالنتيجة ActionErrors من طريقة validate الخاصة بـ FormulaireBean. لكن هنا، هذه القائمة فارغة. عندئذٍ تستخدم وحدة التحكم جزءًا جديدًا من تكوين الإجراء /main:
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
parameter="/vues/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
يقوم وحدة التحكم Struts، عند الضرورة، بإنشاء كائن من النوع المحدد بواسطة السمة type. يتم تنفيذ الطريقة execute لهذه الفئة، ويجب أن تُرجع كائنًا من النوع ActionForward يشير إلى العرض الذي يجب على وحدة التحكم إرساله كاستجابة إلى العميل. وهنا يشير السمة type إلى الفئة المُعرَّفة مسبقًا ForwardAction. لا تقوم الطريقة execute لهذه الفئة بأي شيء، وتكتفي بإرجاع كائن من النوع ActionForward يشير إلى العرض المحدد بواسطة السمة parameter، وهو في هذه الحالة العرض /vues/main.html. وهذا هو بالفعل العرض الذي أرجعته وحدة التحكم.
3.3.7. الاختبار 7
نطلب عرض /formulaire.do مرة أخرى:

نجد النموذج كما تم تأكيده. وقد تم شرح ذلك سابقًا. من خلال الإعداد (scope="session") طلبنا أن يبقى النموذج في الجلسة. وبالتالي يتم الاحتفاظ بقيمه خلال عمليات التبادل بين العميل والخادم.
لقد أوشكنا على الانتهاء. يبقى لنا إنشاء إجراء فعلي في حالة صحة بيانات النموذج. في الوقت الحالي، استخدمنا الإجراء المحدد مسبقًا ForwardAction لتبسيط عرضنا التوضيحي.
3.4. التكوين الجديد للإجراء /main
لن نقوم بتغيير ملف التكوين الحالي struts-config.xml إلا لتعديل قسم /main الخاص به على النحو التالي:
<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>
يشير السمة type الآن إلى فئة أخرى تسمى FormulaireAction والتي سيتعين علينا إنشاؤها. وستتم تنفيذ الطريقة execute الخاصة بهذه الفئة إذا كانت بيانات النموذج frmPersonne صالحة. وقد أوضحنا أن الطريقة execute تؤدي المهمة المطلوبة منها وتُرجع كائنًا من النوع ActionForward يشير إلى العرض الذي يجب على وحدة التحكم إرجاعه إلى العميل. غالبًا ما تكون هناك عدة طرق عرض ممكنة وفقًا لنتيجة معالجة النموذج. يتم سرد قائمة طرق العرض المختلفة الممكنة في علامات <forward> المضمنة في علامة <action>. وصيغة هذه العلامة هي كما يلي:
اسم أي يُحدد طريقة العرض بشكل فريد | |
URL للطريقة المرتبطة بالمفتاح |
3.5. الفئة FormulaireAction
يتمثل كتابة الفئة FormulaireAction بشكل أساسي في كتابة طريقة execute الخاصة بها:
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;
public class FormulaireAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException,ServletException {
// لدينا نموذج صالح، وإلا لما وصلنا إلى هذه المرحلة
FormulaireBean formulaire=(FormulaireBean)form;
request.setAttribute("nom",formulaire.getNom());
request.setAttribute("age",formulaire.getAge());
return mapping.findForward("reponse");
}//تنفيذ
}
تستقبل الدالة execute أربعة معلمات:
- تعيين ActionMapping: كائن "صورة" لإعدادات الإجراء قيد التنفيذ، أي في هذه الحالة صورة للإعدادات التالية:
<action
path="/main"
name="frmPersonne"
validate="true"
input="/erreurs.do"
type="istia.st.struts.personne.FormulaireAction"
>
<forward name="reponse" path="/reponse.do"/>
</action>
وبذلك، يمكن للإجراء الوصول إلى المفاتيح المرتبطة بالطرق التي يمكن إرجاعها إلى العميل عند انتهاء الإجراء. يجب أن تقوم الطريقة التي يتم تنفيذها بإرجاع إحدى هذه المفاتيح.
- ActionForm form: كائن bean الذي يحتوي على قيم النموذج المستخدمة من قبل الإجراء الحالي. هنا، هو الكائن frmPersonne من النوع FormulaireBean. وبذلك، يمكن للإجراء الوصول إلى قيم النموذج.
- HttpServletRequest request: طلب العميل الذي قد تم إثرائه بواسطة سيرفلتات مختلفة. وبذلك، تتوفر للإجراء جميع معلمات الطلب الأصلي (request.getParameter) بالإضافة إلى جميع السمات المضافة إلى هذا الطلب الأصلي (request.getAttribute). في مثالنا، تقوم الطريقة execute بتعزيز الطلب بإضافة الاسم والعمر إليه. وهذا غير ضروري تمامًا هنا لأن هاتين القيمتين موجودتان بالفعل، ولكن كمعلمات وليس كسمات. وقد أُدرج الكود هنا على سبيل المثال فقط.
- HttpServletResponse response: الاستجابة التي سيتم إرسالها إلى العميل. يمكن أن تقوم العملية بإثراء هذه الاستجابة. لكنها لا تفعل ذلك هنا.
نحن هنا في حالة خاصة. لا يوجد لدى الطريقة execute أي عمل تقريبًا. عليها ببساطة أن تشير إلى أن العرض التالي هو العرض /reponse.do وأن تذكر في الطلب أن هذا العرض سيتلقى معلومتي الاسم والعمر اللتين يجب أن يعرضهما. وهي تقوم بذلك باستخدام الطريقة findForward التابعة للفئة ActionMapping، والتي تقبل كمعلمة أحد المفاتيح الموجودة في علامات التوجيه (forward) في تكوين الإجراء. هنا، لا توجد سوى علامة واحدة من هذا النوع:
وبالتالي، فإن طريقتنا «execute» تُرجع قيمة ActionForward التي تحتوي على المفتاح «reponse» للإشارة إلى أنه يجب إرسال العرض /reponse.do.
3.6. اختبارات FormulaireAction
نقوم بتجميع الفئة السابقة باستخدام JBuilder ونضع ملف .class الناتج في WEB-INF/classes:

نقوم بتعديل العرض /vues/reponse.personne.jsp:
<%
// نسترد البيانات: الاسم، العمر
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Personne - réponse</h2>
<hr>
<table>
<tr>
<td>Nom</td>
<td><%= nom %>
</tr>
<tr>
<td>Age</td>
<td><%= age %>
</tr>
</table>
<html:link page="/formulaire.do">
Retour au formulaire
</html:link>
</body>
</html>
تسترد طريقة العرض معلومات الاسم والعمر من سمات الاستعلام الذي تتلقاه. نطلب النموذج من URL http://localhost:8080/strutspersonne/formulaire.do ثم نملؤه:

نستخدم الزر [Envoyer] ونحصل على الرد التالي:

توضيحات:
- سنستخدم الشرح المقدم للاختبار رقم 2 في بداية العملية. ولنتذكر تكوين الإجراء /main:
<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>
- بعد إرسال النموذج إلى وحدة التحكم في URL /main.do، قامت هذه الوحدة بإنشاء أو إعادة استخدام كائن frmPersonne من النوع FormulaireBean وأدرجت فيه قيم النموذج
- تم استدعاء طريقة validate الخاصة بالكائن frmPersonne. ونظرًا لصحة البيانات، فقد أرجعت طريقة validate قائمة ActionErrors فارغة.
- تم إنشاء كائن FormulaireAction أو إعادة استخدامه، وتم استدعاء طريقة execute الخاصة به. وقد أرجعت هذه الطريقة كائن ActionForward بمفتاح "reponse".
- ثم أرسل وحدة التحكم العرض المرتبط بالمفتاح reponse، وهو c.a.d. /reponse.do وبالتالي /vues/reponse.personne.jsp.
- تم عرض الصفحة reponse.personne.jsp بالقيم التي تم إدخالها في الطلب بواسطة طريقة execute الخاصة بالكائن FormulaireAction.
3.7. الخلاصة
لقد قمنا بإنشاء تطبيق كامل ولكنه بسيط. وعند تنفيذه فعليًّا باستخدام Struts وTomcat وJBuilder، توجد فرص عديدة لارتكاب الأخطاء، لا سيما في ملفات تكوين التطبيق XML. للوهلة الأولى، قد يبدو من الأسهل إنشاء هذا التطبيق بدون Struts باستخدام سيرفلت وصفحات JSP. بالنسبة للمبتدئين، قد يكون هذا صحيحًا. ومع اكتساب الخبرة، يصبح التطوير باستخدام Struts أسهل. تفرض العديد من الشركات منهجية Struts في مشاريع تطوير الويب الخاصة بها للأسباب التالية:
- يتوافق Struts مع نموذج MVC
- عندما يعمل جميع المطورين بنفس الطريقة، تصبح صيانة التطبيقات أسهل لأنها تتمتع بهيكلية قياسية.



