7. تطبيق الويب MVC [person] – الإصدار 3
قراءة موصى بها في [ref1]: الفصل 9
7.1. مقدمة
نقترح إضافة كود جافا سكريبت إلى صفحات HTML التي يتم إرسالها إلى المتصفح. والمتصفح هو الذي يقوم بتنفيذ كود جافا سكريبت المضمن في الصفحة التي يعرضها. وهذه التقنية مستقلة عن تلك التي يستخدمها خادم الويب لإنشاء مستند HTML (Java/servlets/JSP، ASP.NET، ASP، PHP، Perl، Python، ...).
[form.jsp]
ستبدو طريقة العرض التي تم إنشاؤها من هذه الصفحة كما يلي:

تستخدم الأزرار التي تحتوي على نص داخل مربع كود JavaScript مضمن في صفحة HTML:
التسمية | نوع HTML | الوظيفة |
<submit> | يعمل كزر [إرسال] في الإصدارات السابقة: يرسل القيم المدخلة إلى وحدة التحكم | |
<button> | زر جديد – يتحقق من صحة البيانات المدخلة محليًا قبل إرسالها إلى وحدة التحكم | |
<reset> | يعيد تعيين النموذج إلى الحالة التي استلمه بها المتصفح في البداية | |
<button> | مسح محتويات حقلَي الإدخال |
فيما يلي مثال على كيفية استخدام زري [إرسال] و[مسح]:
![]() | ![]() |
![]() | ![]() |
سنستخدم أيضًا كود JavaScript للتعامل مع رابط [العودة إلى النموذج] في عرضي [الأخطاء] و[الاستجابة]. لنأخذ عرض [الاستجابة] كمثال:
![]() | 1 ![]() |
يكمن الاختلاف في عنوان URL المعروض في [1]. في الإصدار السابق، كان:
هنا، لم يعد الإجراء جزءًا من عنوان URL لأنه سيتم إرساله عبر طلب POST بدلاً من طلب GET. يعني هذا التغيير أن عنوان URL الوحيد الذي سيعرضه المتصفح سيكون [http://localhost:8080/personne3/main] بغض النظر عن الإجراء المطلوب.
7.2. مشروع Eclipse
لإنشاء مشروع Eclipse [mvc-personne-03] لتطبيق الويب [/personne3]، قم بنسخ مشروع [mvc-personne-02] باتباع الإجراء الموضح في القسم 6.2، الصفحة 78.
![]() | ![]() |
7.3. تكوين تطبيق الويب [personne3]
ملف web.xml لتطبيق /personne3 هو كما يلي:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>mvc-personne-03</display-name>
<!-- ServletPersonne -->
<servlet>
<servlet-name>personne</servlet-name>
<servlet-class>
istia.st.servlets.personne.ServletPersonne
</servlet-class>
<init-param>
<param-name>urlReponse</param-name>
<param-value>
/WEB-INF/vues/reponse.jsp
</param-value>
</init-param>
<init-param>
<param-name>urlErreurs</param-name>
<param-value>
/WEB-INF/vues/erreurs.jsp
</param-value>
</init-param>
<init-param>
<param-name>urlFormulaire</param-name>
<param-value>
/WEB-INF/vues/formulaire.jsp
</param-value>
</init-param>
<init-param>
<param-name>lienRetourFormulaire</param-name>
<param-value>
Retour au formulaire
</param-value>
</init-param>
</servlet>
<!-- Mapping ServletPersonne-->
<servlet-mapping>
<servlet-name>personne</servlet-name>
<url-pattern>/main</url-pattern>
</servlet-mapping>
<!-- welcome files -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
هذا الملف مطابق للملف الموجود في الإصدار السابق باستثناء بعض التفاصيل:
- السطر 6: تغير اسم العرض لتطبيق الويب إلى [mvc-personne-03]
تمت إزالة المعلمة [urlController]. في الإصدار السابق، كانت تُستخدم لتعيين هدف POST لعرض [form]. في هذا الإصدار الجديد، سيكون الهدف هو السلسلة الفارغة، أي عنوان URL الذي يعرضه المتصفح. وقد أوضحنا أن هذا سيكون دائمًا [http://localhost:8080/personne3/main]، وهو ما نحتاجه لطلب POST من عرض [form].
تتغير الصفحة الرئيسية [index.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
response.sendRedirect("/personne3/main");
%>
- السطر 5: تقوم صفحة [index.jsp] بإعادة توجيه العميل إلى عنوان URL لوحدة التحكم [ServletPersonne] في التطبيق [/personne3].
7.4. عرض الكود
7.4.1. عرض [النموذج]
أصبح هذا العرض كما يلي:

يتم إنشاؤه بواسطة صفحة JSP التالية [formulaire.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%// on récupère les données du modèle
String nom = (String) session.getAttribute("nom");
String age = (String) session.getAttribute("age");
%>
<html>
<head>
<title>Personne - formulaire</title>
<script language="javascript">
// -------------------------------
function effacer(){
// on efface les champs de saisie
with(document.frmPersonne){
txtNom.value="";
txtAge.value="";
}//with
}//effacer
// -------------------------------
function envoyer(){
// vérification des paramètres avant de les envoyer
with(document.frmPersonne){
// le nom ne doit pas être vide
champs=/^\s*$/.exec(txtNom.value);
if(champs!=null){
// le nom est vide
alert("Vous devez indiquer un nom");
txtNom.value="";
txtNom.focus();
// retour à l'interface visuelle
return;
}//if
// l'âge doit être un entier positif
champs=/^\s*\d+\s*$/.exec(txtAge.value);
if(champs==null){
// l'âge est incorrect
alert("Age incorrect");
txtAge.focus();
// retour à l'interface visuelle
return;
}//if
// les paramètres sont corrects - on les envoie au serveur
submit();
}//with
}//envoyer
</script>
</head>
<body>
<center>
<h2>Personne - formulaire</h2>
<hr>
<form name="frmPersonne" method="post">
<table>
<tr>
<td>Nom</td>
<td><input name="txtNom" value="<%= nom %>" type="text" size="20"></td>
</tr>
<tr>
<td>Age</td>
<td><input name="txtAge" value="<%= age %>" type="text" size="3"></td>
</tr>
<tr>
</table>
<table>
<tr>
<td><input type="submit" value="Submit"></td>
<td><input type="button" value="[Envoyer]" onclick="envoyer()"></td>
<td><input type="reset" value="Rétablir"></td>
<td><input type="button" value="[Effacer]" onclick="effacer()"></td>
</tr>
</table>
<input type="hidden" name="action" value="validationFormulaire">
</form>
</center>
</body>
</html>
ما الجديد:
- السطر 56: النموذج له اسم [frmPersonne]. سيُستخدم هذا الاسم في كود JavaScript. لاحظ عدم وجود السمة [action]، مما يعني أن النموذج [frmPersonne] سيتم إرساله إلى عنوان URL المعروض في المتصفح.
- السطر 70: زر [Submit] يخدم نفس الغرض الذي يخدمه زر [Envoyer] في الإصدارات السابقة
- السطر 71: يؤدي النقر على زر [Envoyer] (من النوع [Button]) إلى تنفيذ دالة JavaScript [envoyer] المحددة في السطر 24
- السطر 72: لم تتغير وظيفة زر [Reset]
- السطر 73: يؤدي النقر على زر [Clear] (من النوع [Button]) إلى تنفيذ دالة JavaScript [clear] المحددة في السطر 16
قبل التعليق على كود JavaScript، دعونا نستعرض بعض القواعد:
تدير JavaScript الصفحة المعروضة ومحتواها كشجرة من الكائنات التي يكون جذرها هو كائن [document]. قد يحتوي هذا المستند على نموذج واحد أو أكثر. يشير [document.frmPersonne] إلى النموذج المسمى [frmPersonne] المحدد في السطر 56. يحتوي هذا النموذج أيضًا على كائنات. حقول الإدخال هي جزء منه. وبالتالي، يشير [document.frmPersonne.txtName] إلى الكائن الذي يمثل حقل الإدخال HTML المحدد في السطر 60. يحتوي كائن [txtName] على خصائص متنوعة، بما في ذلك خاصية [value]، التي تشير إلى محتوى حقل الإدخال. وبالتالي، يشير [document.frmPersonne.txtName.value] إلى محتوى حقل الإدخال [txtName].
- الأسطر 16–22: تحدد دالة JavaScript [clear] سلسلة فارغة في حقول الإدخال [txtName، txtAge].
- الأسطر 24–49: تتحقق دالة JavaScript [submit] من صحة القيم الموجودة في حقول الإدخال [txtName، txtAge] قبل إرسالها. وتستخدم التعبيرات العادية للقيام بذلك.
- السطر 28: يتحقق مما إذا كانت قيمة حقل الإدخال [txtNom] تتطابق مع النمط /s*، مما يعني صفر أو أكثر من المسافات. إذا كانت الإجابة بنعم، فهذا يعني أن المستخدم لم يدخل اسمًا. إذا كان هناك تطابق مع النمط، فستكون للمتغير `champs` قيمة غير مؤشر null؛ وإلا، فستكون قيمته null.
- السطر 29: إذا كانت هناك مطابقة مع النمط
- السطر 30: عرض رسالة للمستخدم
- السطر 32: نضبط حقل [txtName] على سلسلة فارغة (قد يكون هناك سلسلة من المسافات)
- السطر 33: يتم وضع المؤشر الوامض على حقل [txtName]
- السطر 34: يتم إنهاء الدالة. وبالتالي، لا يتم إرسال القيم المدخلة إلى الخادم.
- الأسطر 38-45: نتبع إجراءً مشابهًا مع حقل [txtAge]
- السطر 47: إذا وصلنا إلى هذه النقطة، فهذا يعني أن القيم المدخلة صحيحة. ثم نرسل النموذج [frmPersonne] إلى خادم الويب. بعد ذلك، تسير الأمور كما لو كنا قد نقرنا على الزر المسمى [Submit].
7.4.2. طريقة العرض [reponse]
تعرض طريقة العرض هذه القيم التي تم إدخالها في النموذج عندما تكون صالحة:
![]() | ![]() |
بالمقارنة مع الإصدار السابق، لا تظهر الميزة الجديدة إلا عند استخدام رابط [العودة إلى النموذج] في عرض [الرد]:
![]() | ![]() |
يكمن الاختلاف في عنوان URL المعروض في [1]. في الإصدار السابق، كان العنوان:
هنا، لم يعد الإجراء جزءًا من عنوان URL لأنه سيتم إرساله عبر طلب POST بدلاً من طلب GET. صفحة JSP الجديدة [reponse.jsp] هي lqqqaaaaaaaaaqqAAAaaa
كما يلي:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
// on récupère les données du modèle
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
<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>
<br>
<form name="frmPersonne" method="post">
<input type="hidden" name="action" value="retourFormulaire">
</form>
<a href="javascript:document.frmPersonne.submit();">
<%= lienRetourFormulaire %>
</a>
</body>
</html>
ما الجديد:
- الأسطر 35-37: يحتوي الرابط [العودة إلى النموذج] على جافا سكريبت. يؤدي النقر على هذا الرابط إلى تشغيل كود جافا سكريبت الموجود في السمة [href]. كما رأينا في دراسة [formulaire.jsp]، نعلم أن هذا الكود يرسل قيم الحقول <input> و<select>... في النموذج [frmPersonne].
- الأسطر 32–34: تحدد النموذج [frmPersonne]. يحتوي هذا النموذج على حقل واحد فقط من النوع <input type="hidden" ...>، أي حقل مخفي. يُستخدم حقل [action] هذا لتمرير اسم الإجراء المطلوب تنفيذه إلى وحدة التحكم، وهو في هذه الحالة [retourFormulaire].
7.4.3. طريقة العرض [errors]
تقوم طريقة العرض هذه بالإبلاغ عن أخطاء الإدخال في النموذج. التغيير الذي تم إجراؤه هو نفسه الذي تم إجراؤه في طريقة العرض [response]:
![]() | ![]() |
يكمن الاختلاف في عنوان URL المعروض في [1]. في الإصدار السابق، كان:
هنا، لم يعد الإجراء جزءًا من عنوان URL لأنه سيتم إرساله عبر طلب POST بدلاً من طلب GET. صفحة JSP الجديدة [response.jsp] هي كما يلي:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ page import="java.util.ArrayList" %>
<%
// on récupère les données du modèle
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<ul>
<%
for(int i=0;i<erreurs.size();i++){
out.println("<li>" + (String) erreurs.get(i) + "</li>\n");
}//for
%>
</ul>
<br>
<form name="frmPersonne" method="post">
<input type="hidden" name="action" value="retourFormulaire">
</form>
<a href="javascript:document.frmPersonne.submit();">
<%= lienRetourFormulaire %>
</a>
</body>
</html>
ما الجديد:
- الأسطر 30-32: الطريقة الجديدة للتعامل مع نقرات الروابط. التفسيرات المقدمة حول هذا الموضوع في دراسة [response.jsp] تنطبق هنا أيضًا.
7.5. اختبار العرض
لاختبار طرق العرض السابقة، نقوم بنسخ صفحات JSP الخاصة بها في مجلد /WebContent/JSP التابع لمشروع Eclipse:

ثم، في مجلد JSP، يتم تعديل الصفحات على النحو التالي:
[form.jsp]:
...
<%
// -- test : on crée le modèle de la page
session.setAttribute("nom","tintin");
session.setAttribute("age","30");
%>
<%// on récupère les données du modèle
String nom = (String) session.getAttribute("nom");
String age = (String) session.getAttribute("age");
%>
تمت إضافة السطرين 4 و5 لإنشاء النموذج المطلوب للصفحة في السطرين 9 و10.
[reponse.jsp]:
...
<%
// -- test : on crée le modèle de la page
request.setAttribute("nom","milou");
request.setAttribute("age","10");
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// on récupère les données du modèle
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
...
تمت إضافة الأسطر 4–6 لإنشاء القالب المطلوب للصفحة في الأسطر 11–13.
[errors.jsp]:
<%
// -- test : on crée le modèle de la page
ArrayList<String> erreurs1=new ArrayList<String>();
erreurs1.add("erreur1");
erreurs1.add("erreur2");
request.setAttribute("erreurs",erreurs1);
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// on récupère les données du modèle
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
تمت إضافة الأسطر 4-8 لإنشاء النموذج المطلوب للصفحة في الأسطر 13-14.
قم بتشغيل Tomcat إذا لم تكن قد قمت بذلك بالفعل، ثم اطلب عناوين URL التالية:
![]() | ![]() |
![]() |
نحصل على عدد المشاهدات المتوقع.
7.6. وحدة التحكم [ServletPersonne]
ستتولى وحدة التحكم [ServletPersonne] الخاصة بتطبيق الويب [/personne3] معالجة الإجراءات التالية:
لا. | الطلب | المصدر | المعالجة |
1 | [GET /person3/hand] | عنوان URL الذي أدخله المستخدم | - إرسال [نموذج] فارغ |
2 | [POST /person3/main] مع المعلمات [txtName, txtAge، action=validateForm] المنشورة | انقر على [إرسال] في [form] | - تحقق من قيم معلمات [txtName، txtAge] - إذا كانت غير صحيحة، أرسل عرض [errors(errors)] - إذا كانت صحيحة، أرسل عرض [response(name,age)] |
3 | [POST /person3/main] مع المعلمات [action=returnForm] المستضافة | انقر على [العودة إلى النموذج] المشاهدات [response] و [errors]. | - إرسال نموذج العرض [form] بعد ملئه مسبقًا بأحدث القيم التي تم إدخالها |
وبالتالي، لدينا إجراء جديد يجب التعامل معه: [POST /person3/main] مع المعلمة المرسلة [action=returnForm]. بدلاً من الإجراء القديم [GET /person3/main?action=returnForm].
7.6.1. هيكل وحدة التحكم
هيكل وحدة التحكم [ServletPersonne] مطابق لهيكل الإصدار السابق.
ما الجديد:
- السطر 11: لم يعد المصفوف [parameters] يحتوي على المعلمة [urlController]، التي تمت إزالتها من ملف [web.xml].
لم تتغير طرق [init، doValidationFormulaire]. أما طرق [doGet، doInit، doRetourFormulaire] فقد تغيرت قليلاً.
7.6.2. طريقة [doGet]
يجب أن تتعامل طريقة [doGet] مع الإجراء [POST /person3/main] مع المعلمة المرسلة [action=returnForm]:
- الأسطر 6-9: معالجة الإجراء [POST /person3/main] باستخدام المعلمة المرسلة [action=returnForm]
7.6.3. طريقة [doInit]
تتعامل هذه الطريقة مع الطلب رقم 1 [GET /person3/hand]. وفيما يلي شفرة هذه الطريقة:
التغيير هو أن عرض [form] المعروض في السطر 8 لم يعد يحتوي على عنصر [action] في قالبه.
7.6.4. طريقة [doRetourFormulaire]
تقوم هذه الطريقة بمعالجة الطلب رقم 1 [POST /person3/main] مع [action=formSubmit] في العناصر المرسلة. وفيما يلي شفرة هذه الطريقة:
التغيير هو أن عرض [form] المعروض في السطر 14 لم يعد يحتوي على عنصر [action] في قالبه.
7.7. الاختبارات
ابدأ أو أعد تشغيل Tomcat بعد دمج مشروع Eclipse [personne-mvc-03] فيه. اطلب عنوان URL [http://localhost:8080/personne3] ثم كرر الاختبارات الموضحة كمثال في القسم 7.1.















