11. المثال 09 - تحويل الأعداد الصحيحة والتحقق من صحتها
سنلقي الآن نظرة على سلسلة من الأمثلة حول تحويل معلمات النموذج والتحقق من صحتها. المشكلة هي كما يلي. لمعالجة عنوان URL من النموذج [http://machine:port/.../Action]، يقوم وحدة التحكم [FilterDispatcher] بإنشاء مثيل للفئة التي تنفذ الإجراء المطلوب وتنفيذ إحدى طرقها — بشكل افتراضي، الطريقة المسماة execute. يمر استدعاء طريقة execute هذه عبر سلسلة من المعترضات:
![]() |
يتم تعريف قائمة المعترضات في ملف [struts-default.xml] الموجود في جذر أرشيف [struts2-core.jar]. قائمة المعترضات المحددة هناك هي كما يلي:
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
من بين المعترضات، هناك واحدة مسؤولة عن إدخال قيم المعلمات المرفقة بالطلب إلى الإجراء بالصيغة parami=values. ونعلم أن القيم ستُدخل إلى حقل parami في الإجراء عبر طريقة setParami إن كانت موجودة. وإلا، فلن يتم الإدخال ولن يتم الإبلاغ عن أي خطأ.
السلسلة parami=values هي سلسلة أحرف. حتى الآن، تم إدخال القيم في حقول parami من النوع String:
لم يشكل إدخال السلسلة valeuri كقيمة لسلسلة parami أي مشكلة. إذا لم يكن parami من النوع String، فيجب تحويل valeuri إلى النوع Ti الخاص بـ parami. هذه هي مشكلة التحويل. على سبيل المثال، قد نرغب في أن يكون العمر عددًا صحيحًا ونكتب في الإجراء:
علاوة على ذلك، قد نرغب في تقييد العمر بين 1 و 150. وهذا يمثل مشكلة في التحقق من الصحة. يمكن تحويل المعلمة parami إلى النوع الصحيح دون أن تكون بالضرورة صالحة. لذلك، هناك خطوتان يجب إكمالهما. بالعودة إلى مخطط معالجة الطلب:
![]() |
سيتولى معتقلان معالجة تحويل المعلمات والتحقق من صحتها، على التوالي. إذا فشلت أي من الخطوتين، فلن ينتقل الطلب إلى الإجراء (المسار الأحمر أعلاه). يتم إعادة عرض النموذج الذي تم من خلاله إرسال المعلمات غير الصحيحة مع رسائل الخطأ.
المعترضان المشاركان في تحويل المعلمات والتحقق من صحتها هما معترضان conversionError و validation في السطرين 19 و 20 من قائمة المعترضين الموضحة سابقًا. لاحظ في الأسطر 20–22 أن معترض التحقق من الصحة لا يُطبق إذا كانت الطريقة المستدعاة هي إحدى طرق input أو back أو cancel أو browse. سنستخدم هذه الخاصية لاحقًا.
سنبدأ بفحص تحويل الأعداد الصحيحة والتحقق من صحتها. سنقضي بعض الوقت في هذا المثال الأول لأن عملية التحقق من الصحة تتضمن العديد من العناصر. وبمجرد فهمنا لهذه العناصر، سننتقل بسرعة أكبر عبر الأمثلة التالية.
11.1. النموذج
![]() |
- في [1]، نموذج الإدخال
- في [2]، والنتيجة عند التحقق من صحة البيانات دون إدخال أي قيم
11.2. مشروع NetBeans
مشروع NetBeans هو كما يلي:
![]() |
- في [1]، العروض الثلاثة للتطبيق
- في [2]، شفرة المصدر وملفات الرسائل المُعَلَّمة وملفات تكوين Struts.
11.3. تكوين Struts
يتم تكوين التطبيق بواسطة ملفات [struts.xml] و [example.xml].
ملف [struts.xml] هو كما يلي:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.custom.i18n.resources" value="messages" />
<include file="example/example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Accueil</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
</struts>
تحدد الأسطر 12–18 الإجراء [/example/Home] باعتباره الإجراء الافتراضي عندما لا يحدد المستخدم إجراءً معينًا.
ملف [example.xml] كما يلي:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Accueil">
<result name="success">/example/Accueil.jsp</result>
</action>
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Accueil.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
</package>
</struts>
- الأسطر 8–10: تعرض الإجراء [Home] طريقة العرض [Home.jsp]
- السطر 11: يقوم الإجراء [FormInt] بتنفيذ طريقة execute الخاصة بفئة [example.FormInt] بشكل افتراضي. وسنرى أنه سيتم تنفيذ طريقتين أخريين: طريقتا input و cancel. وسيتم بعد ذلك تحديد هاتين الطريقتين في معلمات الطلب.
- السطر 12: سيعرض مفتاح input طريقة العرض [FormInt.jsp] (السطر 5). طريقة العرض هذه هي طريقة عرض النموذج.
- السطر 13: سيتم إرجاع مفتاح cancel بواسطة طريقة cancel المرتبطة بالرابط [Cancel]. سيكون العرض المعروض بعد ذلك هو عرض [Home.jsp] بعد إعادة التوجيه (type=redirect).
- السطر 14: يتم إرجاع مفتاح `success` بواسطة طريقة `execute` الخاصة بعملية [FormInt]. إذا وصل الطلب إلى طريقة `execute`، فهذا يعني أنه قد اجتاز بنجاح جميع المعترضات، خاصة تلك التي تتحقق من صحة المعلمات. ثم تقوم طريقة `execute` ببساطة بإرجاع مفتاح `success`، والذي سيعرض عرض التأكيد [ConfirmationInt.jsp].
11.4. ملفات الرسائل
ملف [messages.properties] كما يلي:
Accueil.titre=Accueil
Accueil.message=Struts 2 - Conversions et validations
Accueil.FormInt=Saisie de nombres entiers
Form.titre=Conversions et validations
FormInt.message=Struts 2 - Conversion et validation de nombres entiers
Form.submitText=Valider
Form.cancelText=Annuler
Form.clearModel=Raz mod\u00e8le
Confirmation.titre=Confirmation
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.lien=Formulaire de test
بالإضافة إلى هذا الملف، تستخدم طرق العرض ملف [FormInt.properties] التالي:
int1.prompt=1-Nombre entier positif de deux chiffres
int1.error=Tapez un nombre entier positif de deux chiffres
int2.prompt=2-Nombre entier
int2.error=Tapez un nombre entier
int3.prompt=3-Nombre entier >=-1
int3.error=Tapez un nombre entier >=-1
int4.prompt=4-Nombre entier <=10
int4.error=Tapez un nombre entier <=10
int5.prompt=5-Nombre entier dans l''intervalle [1,10]
int5.error=Tapez un nombre entier dans l''intervalle [1,10]
int6.prompt=6-Nombre entier dans l''intervalle [2,20]
int6.error=Tapez un nombre entier dans l''intervalle [2,20]
يُستخدم ملف [FormInt.properties] فقط عندما يكون الإجراء الذي أنشأ العرض هو الإجراء [FormInt]. هذه طريقة لتقسيم ملف الرسائل إذا أصبح حجمه كبيرًا جدًا. يتم ترجمة الرسائل الخاصة بالإجراء Action في ملف [Action.properties].
11.5. طرق العرض والإجراءات
سنقدم الآن طرق العرض والإجراءات الخاصة بالتطبيق. استنادًا إلى تكوين التطبيق:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Accueil">
<result name="success">/example/Accueil.jsp</result>
</action>
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Accueil.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
</package>
</struts>
يمكننا أن نرى أن هناك ثلاث طرق عرض [Home.jsp، FormInt.jsp، ConfirmationFormInt.jsp] وعمليتين [Home، FormInt].
11.5.1. Home.jsp
الطريقة [Home.jsp] هي كما يلي:

وإليك شفرة البرنامج:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Accueil.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Accueil.message"/></h2>
<ul>
<li>
<s:url id="url" action="FormInt!input"/>
<s:a href="%{url}"><s:text name="Accueil.FormInt"/></s:a>
</li>
</ul>
</body>
</html>
الرابط الموجود في السطر 14 يُنشئ كود HTML التالي:
<a href="<a href="view-source:http://localhost:8084/exemple-09/example/FormInt.action">/exemple-09/example/FormInt!input.action</a>">Saisie de nombres entiers</a>
وبالتالي، هذا رابط إلى الإجراء [FormInt] الذي تم تكوينه على النحو التالي في ملف [example.xml]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Accueil.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
سيؤدي النقر على الرابط إلى إنشاء مثيل لفئة [example.FormInt] وتنفيذ طريقة الإدخال الخاصة بها. ونظرًا لعدم وجودها، سيتم تنفيذ طريقة الإدخال الخاصة بفئة ActionSupport الأصلية. لا تقوم هذه الطريقة بأي شيء سوى إرجاع مفتاح الإدخال. وبالتالي، سيتم عرض طريقة العرض [/example/FormInt.jsp].
علاوة على ذلك، تعد طريقة الإدخال إحدى الطرق التي يتجاهلها مانع التحقق من الصحة:
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
وبالتالي، لن يتم التحقق من صحة المعلمات. وهذا أمر مهم لأنه لا توجد معلمات هنا، وسنرى لاحقًا أن قواعد التحقق من الصحة تتطلب وجود ست معلمات.
11.5.2. الإجراء [FormInt]
يرتبط الإجراء [FormInt] بالفئة [FormInt] التالية:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.interceptor.validation.SkipValidation;
public class FormInt extends ActionSupport implements ModelDriven, SessionAware {
// constructor without parameters
public FormInt() {
}
// action model
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
public String cancel() {
// cleaning the model
((FormIntModel) getModel()).clearModel();
// result
return "cancel";
}
@SkipValidation
public String clearModel() {
// close to the model
((FormIntModel) getModel()).clearModel();
// result
return INPUT;
}
// SessionAware
private Map<String, Object> session;
public void setSession(Map<String, Object> session) {
this.session = session;
}
// validation
@Override
public void validate() {
// valid int6 input?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
}
}
سنعلق على هذا الكود حسب الحاجة. في الوقت الحالي:
- السطر 9، تنفذ فئة [FormInt] واجهتين:
- ModelDriven، التي تحتوي على طريقة واحدة فقط، وهي getModel في السطر 16
- SessionAware، التي تحتوي على طريقة واحدة فقط، وهي setSession في السطر 41
- السطور 16–21: تنفيذ واجهة ModelDriven. تذكر أن هذه الواجهة تسمح بتفويض نموذج العرض إلى فئة خارجية، وهي في هذه الحالة الفئة [FormIntModel] التالية:
package example;
public class FormIntModel {
// constructor without parameters
public FormIntModel() {
}
// form fields
private String int1;
private Integer int2;
private Integer int3;
private Integer int4;
private Integer int5;
private String int6;
// raz model
public void clearModel(){
int1=null;
int2=null;
int3=null;
int4=null;
int5=null;
int6=null;
}
// getters and setters
...
}
يحتوي نموذج [FormIntModel] على ستة حقول تتوافق مع حقول الإدخال الستة في عرض [FormInt.jsp]. ستستقبل هذه الحقول الستة القيم المرسلة. أربعة منها من النوع Integer. لذلك، ستنشأ مشكلة تحويل String إلى Integer بالنسبة لها. تسمح لك طريقة clearModel بإعادة تعيين النموذج.
لنعد إلى طريقة getModel الخاصة بعملية [FormInt]:
// action model
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
- الأسطر 3–5: يتم استرداد النموذج من الجلسة. وإذا لم يكن موجودًا، يتم إنشاء مثيل للنموذج ووضعه في الجلسة.
- السطر 6: بينما يتم إنشاء مثيل للإجراء مع كل طلب جديد يتم إرساله إلى الإجراء، يبقى نموذجه في الجلسة.
نلاحظ أن الفئة لا تحدد طريقة إدخال، لكن الفئة الأم تحتوي على طريقة تعيد مفتاح الإدخال. يؤدي تنفيذ هذه الطريقة إلى عرض طريقة العرض [FormInt.jsp]، التي سنقدمها الآن.
11.5.3. طريقة العرض [FormInt.jsp]
عرض [FormInt.jsp] هو كما يلي:
![]() |
- في [1]، النموذج الفارغ
- في [2]، النموذج بعد التحقق من صحة المعلمات غير الصحيحة.
وإليك الكود الخاص به:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="FormInt.message"/></h2>
<s:form name="formulaire" action="FormInt">
<s:textfield name="int1" key="int1.prompt"/>
<s:textfield name="int2" key="int2.prompt"/>
<s:textfield name="int3" key="int3.prompt"/>
<s:textfield name="int4" key="int4.prompt"/>
<s:textfield name="int5" key="int5.prompt"/>
<s:textfield name="int6" key="int6.prompt"/>
<s:submit key="Form.submitText" method="execute"/>
</s:form>
<br/>
<s:url id="url" action="FormInt" method="cancel"/>
<s:a href="%{url}"><s:text name="Form.cancelText"/></s:a>
<br/>
<s:url id="url" action="FormInt" method="clearModel"/>
<s:a href="%{url}"><s:text name="Form.clearModel"/></s:a>
</body>
</html>
- الأسطر 12–17: حقول الإدخال الستة المطابقة للحقول الستة في نموذج [FormIntModel] الخاص بعملية [FormInt]. عند عرض العرض، تُستخدم سمات القيمة لحقول الإدخال للقيم التي تعرضها هذه الحقول. إذا كانت سمة القيمة مفقودة، يتم استخدام سمة الاسم.
- السطر 12: حقل الإدخال مرتبط (name) بحقل int1 الخاص بالإجراء أو نموذجه إذا كان الإجراء ينفذ واجهة ModelDriven. وهذا هو الحال هنا. وينطبق هذا أيضًا على جميع الحقول الأخرى.
- السطر 18: يقوم الزر [Submit] بإرسال الإدخالات إلى الإجراء [FormInt] المحدد في السطر 11. وسيتم تنفيذ طريقة execute الخاصة به.
- السطران 21-22: ينفذ الرابط [Cancel] طريقة [FormInt.cancel].
- السطران 24-25: ينفذ الرابط [Clear Model] طريقة [FormInt.clearModel].
11.5.4. طريقة العرض [ConfirmationFormInt.jsp]
![]() |
يتم عرضه عندما تكون جميع الإدخالات في النموذج [FormInt.jsp] صالحة.
- في [1]، يتم إرسال القيم الصحيحة
- في [2]، صفحة التأكيد
في [2]، صفحة التأكيد
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Confirmation.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="int1.prompt"/></td>
<td><s:property value="int1"/></td>
</tr>
<tr>
<td><s:text name="int2.prompt"/></td>
<td><s:property value="int2"/></td>
</tr>
<tr>
<td><s:text name="int3.prompt"/></td>
<td><s:property value="int3"/></td>
</tr>
<tr>
<td><s:text name="int4.prompt"/></td>
<td><s:property value="int4"/></td>
</tr>
<tr>
<td><s:text name="int5.prompt"/></td>
<td><s:property value="int5"/></td>
</tr>
<tr>
<td><s:text name="int6.prompt"/></td>
<td><s:property value="int6"/></td>
</tr>
</table>
<br/>
<s:url id="url" action="FormInt" method="input"/>
<s:a href="%{url}"><s:text name="Confirmation.lien"/></s:a>
</body>
</html>
لفهم هذا الرمز، تذكر أن العرض يتم عرضه بعد إنشاء مثيل لفئة [FormInt]. وبالتالي، يمكن للعرض الوصول إلى حقول هذه الفئة ونموذجها [FormIntModel].
- الأسطر 16–38: يتم عرض قيم الحقول الستة
- الأسطر 42-43: رابط إلى الإجراء [FormInt]. الشفرة التي تم إنشاؤها لهذا الرابط هي كما يلي:
<a href="/exemple-09/example/FormInt!input.action">Formulaire de test</a>
يشير عنوان URL المحدد للرابط إلى أن طريقة الإدخال الخاصة بعملية [FormInt] يجب أن تتعامل مع الطلب. تذكر تكوين عملية [FormInt] في [example.xml]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Accueil.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
ستكون طريقة الإدخال لفئة [FormInt] هي طريقة الإدخال لفئتها الأم، ActionSupport. يتم تنفيذ طريقة الإدخال لفئة [FormInt] بعد تنفيذ المعترضات
![]() |
نحن نعلم أن استدعاء طريقة الإدخال يتم تجاهله بواسطة مانع التحقق من الصحة. لذلك، لن يتم إجراء أي تحقق من الصحة.
يتم عرض طريقة العرض [FormInt.jsp]:
![]() |
في [2]، تعود حقول الإدخال إلى قيمها الافتراضية. قد يبدو هذا أمرًا طبيعيًا، لكنه ليس كذلك. نظرًا لاستدعاء الإجراء [FormInt]، تم إنشاء مثيل للفئة [FormInt] المرتبطة به. ولأن هذه الفئة تنفذ واجهة ModelDriven، تم استدعاء طريقة getModel الخاصة بها:
// action model
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
يمكننا أن نرى أن نموذج الإجراء يتم استرداده من الجلسة. في الخطوة السابقة، تم تحديث هذا النموذج بالقيم المرسلة. لذلك نسترد هذه القيم. لو لم نضع النموذج في الجلسة، لكان لدينا ستة حقول فارغة في عرض [FormInt.jsp].
11.5.5. الإجراء [FormInt!clearModel]
يتم تشغيل الإجراء [FormInt!clearModel] بالنقر فوق الرابط [Clear Model]:
![]() |
- في [1]، النموذج بعد إدخال بيانات غير صحيحة
- في [2]، النموذج بعد النقر على رابط [Clear Model].
طريقة [FormInt.clearModel] هي كما يلي:
@SkipValidation
public String clearModel() {
// close to the model
((FormIntModel) getModel()).clearModel();
// result
return INPUT;
}
- السطر 1: لا يوجد أي تحقق من الصحة يجب إجراؤه. نستخدم تعليق @SkipValidation للإشارة إلى ذلك. وبالتالي، لن يقوم مانع التحقق من الصحة بإجراء أي عمليات تحقق.
- السطر 4: يتم تنفيذ طريقة [FormIntModel].clearModel. لقد صادفناها من قبل. وهي تعيد تعيين الحقول الستة للنموذج إلى null.
- السطر 7: تُرجع الطريقة مفتاح الإدخال.
بالعودة إلى تكوين الإجراء [FormInt]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Accueil.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
يمكننا أن نلاحظ أن الضغط على مفتاح الإدخال سيؤدي إلى عرض نموذج [FormInt.jsp]. يعرض هذا النموذج الحقول الستة الخاصة بالنموذج. ونظرًا لأن قيم هذه الحقول فارغة، فإن النموذج يعرض ستة حقول فارغة [2].
11.5.6. الإجراء [FormInt!cancel]
يتم تشغيل الإجراء [FormInt!cancel] بالنقر فوق الرابط [Cancel]:
![]() |
- في [1]، النموذج بعد إدخال بيانات غير صحيحة
- في [2]، الصفحة الرئيسية بعد النقر على رابط [Cancel].
طريقة [FormInt.cancel] هي كما يلي:
public String cancel() {
// cleaning the model
((FormIntModel) getModel()).clearModel();
// result
return "cancel";
}
- السطر 1: لاحظ أن الطريقة لا يسبقها تعليق SkipValidation. ومع ذلك، لا نريد إجراء عمليات التحقق من الصحة. طريقة cancel هي إحدى الطرق الأربع (input، back، cancel، browse) التي يتجاهلها مانع التحقق من الصحة، لذا فإن تعليق SkipValidation ليس ضروريًا.
- السطر 3: هذا يمسح النموذج
- السطر 5: يعيد مفتاح الإلغاء
العودة إلى تكوين الإجراء [FormInt]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Accueil.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
يمكننا أن نرى أن مفتاح "cancel" سيعرض طريقة العرض [Home.jsp] بعد إعادة توجيه من جانب العميل. ويظهر هذا في طريقة العرض [2].
11.6. عملية التحقق من الصحة
سنقوم الآن بمعالجة التحقق من صحة حقول الإدخال الستة المرتبطة بالحقول الستة التالية في النموذج:
// champs du formulaire
private String int1;
private Integer int2;
private Integer int3;
private Integer int4;
private Integer int5;
private String int6;
يتم إجراء هذا التحقق من الصحة في كل مرة يتم فيها إنشاء مثيل لفئة [FormInt] ولا يتم تجاهل الطريقة المنفذة بواسطة مانع التحقق من الصحة. ويتم التحكم فيه بواسطة:
- ملف [FormInt-validation.xml]، إذا كان موجودًا في نفس المجلد الذي توجد فيه فئة [FormInt]
- طريقة [FormInt.validate]، إذا كانت موجودة.
![]() |
- في [1]: ملف [xwork-validator-1.0.2.dtd] المطلوب لعملية التحقق من الصحة
- في [2]: ملف [FormInt-validation.xml] الموجود في نفس المجلد الذي توجد فيه فئة [FormInt]
ملف [FormInt-validation.xml] هو كما يلي:
<!--
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
-->
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://localhost:8084/exemple-09/example/xwork-validator-1.0.2.dtd">
<validators>
<field name="int1" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int1.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{2}$</param>
<param name="trim">true</param>
<message key="int1.error"/>
</field-validator>
</field>
<field name="int2" >
...
</field>
...
</validators>
- في [3]، عنوان URL الخاص بـ DTD (تعريف نوع المستند) لملف التحقق من الصحة. يجب أن يكون هذا العنوان متاحًا؛ وإلا، فلن يتم استخدام ملف التحقق من الصحة.
- في [7]، عنوان URL الخاص بـ DTD الذي يستخدمه التطبيق. لقد وضعنا ملف DTD في مجلد [example] الخاص بمشروع example-09 [1] بحيث يكون متاحًا حتى في حالة عدم وجود اتصال بالإنترنت.
- الأسطر 11–20: قم بتعيين شروط التحقق من صحة المعلمة int1 المرتبطة بحقل int1 في النموذج.
العلامة المسماة int1 في النموذج هي كما يلي:
<s:textfield name="int1" key="int1.prompt" />
يتم تعريف الحقل int1 في النموذج على النحو التالي:
private String int1;
- الأسطر 12–14: تحقق من وجود المعلمة int1 (ليست فارغة) وأن طولها غير صفر. إذا لم يكن الأمر كذلك، تظهر رسالة خطأ مرتبطة بحقل الإدخال. يتم تعريفها في [FormInt.properties] على النحو التالي:
int1.error=Tapez un nombre entier positif de deux chiffres
في حالة وجود خطأ، تتوقف عملية التحقق من صحة المعلمة int1 (short-circuit=true).
- الأسطر 15-19: يتم التحقق من صحة المعلمة int1 باستخدام تعبير عادي.
- السطر 16: التعبير العادي، في هذه الحالة رقمان بدون أي شيء قبلهما أو بعدهما.
- السطر 17: قبل مقارنتها بالتعبير العادي، ستتم إزالة المسافات البادئة والنهائية من المعلمة int1.
- السطر 18: رسالة الخطأ، إن وجدت. وهي نفس الرسالة الخاصة بأداة التحقق من الصحة السابقة.
لنرى كيف يعمل هذا:
![]() |
- في [1]، إدخال غير صحيح لحقل int1
- في [2]، الصفحة التي تم إرجاعها:
- يتم عرض رسالة الخطأ الخاصة بمفتاح int1.error. وهي باللون الأحمر.
- تظهر تسمية الحقل غير الصحيح باللون الأحمر أيضًا.
- يتم عرض الإدخال غير الصحيح مرة أخرى. يجب توقع ذلك لأنه ليس بالضرورة السلوك الافتراضي.
لقد رأينا أن التحقق من صحة النموذج يؤدي إلى تشغيل طريقة [FormInt].execute إذا تمكن الطلب من اجتياز جميع المعترضات، ولا سيما معترض التحقق من الصحة:
![]() |
- إذا وصل الطلب إلى طريقة `execute` الخاصة بالإجراء، فإنه يُرجع مفتاح النجاح إلى وحدة التحكم، كما رأينا.
- إذا أوقف مانع التحقق الطلب لأن المعلمات التي تم اختبارها غير صالحة، يتم إرجاع مفتاح `input` إلى وحدة التحكم.
نظرًا لأن الإجراء [FormInt] تم تكوينه على النحو التالي:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Accueil.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
عندما يكون هناك خطأ في التحقق من الصحة، يتم عرض طريقة العرض [FormInt.jsp]، أي النموذج. تم تصميم علامات Struts لعرض أي رسائل خطأ مرتبطة بها. لذلك سنرى طريقة العرض [FormInt.jsp] مع رسائل خطأ مرفقة بالحقول المختلفة. يظهر هذا في طريقة العرض [2].
دعونا الآن نفحص التحقق من صحة الحقل int2، المعلن كما يلي في النموذج:
private Integer int2;
التحقق من صحة الحقل int2 في [FormInt-validation.xml] هو كما يلي:
<field name="int2" >
<field-validator type="required" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
</field>
- الأسطر 2–4: تحقق من وجود المعلمة int2.
- الأسطر 5-7: تحقق من إمكانية تحويل السلسلة إلى عدد صحيح
- السطران 3 و6: رسالة الخطأ الخاصة بمفتاح int2.error هي كما يلي:
int2.error=Tapez un nombre entier
التحقق من صحة الحقل Integer int3 في النموذج في [FormInt-validation.xml] هو كما يلي:
<field name="int3" >
<field-validator type="required" short-circuit="true">
<message key="int3.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">-1</param>
<message key="int3.error"/>
</field-validator>
</field>
- الأسطر 8–11: تحقق من أن الحقل int3 هو عدد صحيح >= -1
- السطران 3 و7: رسالة الخطأ لمفتاح int3.error هي كما يلي:
int3.error=Tapez un nombre entier >=-1
التحقق من صحة الحقل الصحيح int4 في النموذج في [FormInt-validation.xml] هو كما يلي:
<field name="int4" >
<field-validator type="required" short-circuit="true">
<message key="int4.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="max">10</param>
<message key="int4.error"/>
</field-validator>
</field>
- الأسطر 8-11: تحقق من أنه عدد صحيح <=10
- السطران 3 و7: رسالة الخطأ لمفتاح int4.error هي كما يلي:
int4.error=Tapez un nombre entier <=10
التحقق من صحة الحقل الصحيح int5 في النموذج الموجود في [FormInt-validation.xml] هو كما يلي:
<field name="int5" >
<field-validator type="required" short-circuit="true">
<message key="int5.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">1</param>
<param name="max">10</param>
<message key="int5.error"/>
</field-validator>
</field>
- الأسطر 5–9: تحقق من أن القيمة عدد صحيح في النطاق [1، 10].
- السطران 3 و8: رسالة الخطأ لمفتاح int5.error هي كما يلي:
int5.error=Tapez un nombre entier dans l''intervalle [1,10]
التحقق من صحة حقل String int6 في النموذج الموجود في [FormInt-validation.xml] هو كما يلي:
<field name="int6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{1,2}$</param>
<param name="trim">true</param>
<message key="int6.error"/>
</field-validator>
</field>
- الأسطر 5–9: تحقق من أن int6 عبارة عن سلسلة مكونة من رقمين.
- السطران 3 و8: رسالة الخطأ لمفتاح int6.error هي كما يلي:
int6.error=Tapez un nombre entier dans l''intervalle [2,20]
لا يتحقق التحقق السابق من أن المعلمة int6 هي عدد صحيح في النطاق [2,20]. يتم إجراء هذا الفحص في طريقة [FormInt].validate، التي يتم تنفيذها بعد معالجة ملف [FormInt-validation.xml]. هذه الطريقة هي كما يلي:
// validation
@Override
public void validate() {
// valid int6 input?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
}
- السطر 5: نتحقق مما إذا كانت هناك أية أخطاء مرتبطة بحقل int6. إذا كان الأمر كذلك، نتوقف هنا.
- السطر 6: إذا لم تكن هناك أخطاء، نسترد حقل int6 String من النموذج ونحوله إلى عدد صحيح.
- السطر 7: نتحقق من أن العدد الصحيح الذي تم استرداده يقع في النطاق [2,20].
- السطر 8: إذا لم يكن الأمر كذلك، يتم إرفاق رسالة خطأ بحقل int6. يتم استرداد رسالة الخطأ هذه من ملف الرسائل باستخدام المفتاح int6.error.
إذا تم العثور على أخطاء في نهاية عملية التحقق هذه، يتم إنهاء استدعاء طريقة [FormInt].execute، ويتم إرجاع مفتاح الإدخال إلى وحدة التحكم Struts.
![]() |
11.7. التفاصيل النهائية
لقد رأينا عدة طرق لإدخال الأعداد الصحيحة. وهي ليست جميعها متكافئة. لنأخذ، على سبيل المثال، حقلي الإدخال int5 و int6:
في عرض [FormInt.jsp]، تم تعريفهما على النحو التالي:
<s:textfield name="int5" key="int5.prompt"/>
<s:textfield name="int6" key="int6.prompt"/>
يتم تعريف نموذجها في [FormIntModel.java]:
private Integer int5;
private String int6;
الحقل int5 من النوع Integer، بينما الحقل int6 من النوع String. قواعد التحقق من صحة كل منهما مختلفة:
<field name="int5" >
<field-validator type="required" short-circuit="true">
<message key="int5.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">1</param>
<param name="max">10</param>
<message key="int5.error"/>
</field-validator>
</field>
<field name="int6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{1,2}$</param>
<param name="trim">true</param>
<message key="int6.error"/>
</field-validator>
</field>
يتم التحقق من صحة حقل int6 بواسطة طريقة validate الخاصة بعملية [FormInt]:
public void validate() {
// valid int6 input?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
على الرغم من اختلاف صياغتهما، تهدف قاعدتا التحقق من الصحة إلى التأكد من أن القيمة المدخلة هي عدد صحيح ضمن نطاق محدد. ومع ذلك، يختلف سلوك الحقلين int5 و int6 أثناء وقت التشغيل، كما هو موضح في لقطات الشاشة التالية:
![]() |
- في [1]، نفس الإدخال غير الصحيح لكلا الحقلين
- في [2]، تم عرض صفحة الخطأ. يحتوي الحقلان على رسائل خطأ مختلفة.
- في [3]، تظهر رسالة غير مرغوب فيها للحقل int5 لأنها باللغة الإنجليزية. وينتج ذلك عن فشل تحويل السلسلة إلى عدد صحيح. هناك أيضًا استثناء في سجلات Apache:
ومن الغريب أن Struts بحث عن طريقة FormIntModel.setInt5(String value) ولكنه لم يتمكن من العثور عليها.
المفتاح الخاص برسالة الخطأ هو xwork.default.invalid.fieldvalue. لترجمتها إلى الفرنسية، ما عليك سوى ربط نص باللغة الفرنسية بهذا المفتاح. لذلك نضيف السطر التالي إلى ملف [messages.properties]:
...
xwork.default.invalid.fieldvalue=Valeur invalide pour le champ "{0}".
11.8. الخلاصة
بهذا نختتم دراستنا لهذا التطبيق الأول المخصص للتحقق من صحة المعلمات. كان شرحه معقدًا. سنقوم الآن بفحص تطبيقات مشابهة. لذلك، سنكتفي بالتعليق على ما تغير فقط.














