12. تطبيق الويب MVC [personne] – الإصدار 7
12.1. مقدمة
في هذا الإصدار، نفترض أنه قد تكون هناك متصفحات عملاء قامت بتعطيل:
- إعادة توجيه ملفات تعريف الارتباط التي يرسلها الخادم
- تنفيذ كود جافا سكريبت المضمن في الصفحات HTML المعروضة
ومع ذلك، نريد أن يتمكن هذا النوع من المتصفحات من استخدام تطبيقنا. النقطة 2 تعيدنا إلى الإصدار 2 من تطبيقنا، حيث تم استخدام جافا سكريبت بدءًا من الإصدار 3. كان الإصدار 2 يشغل التطبيق بدون جافا سكريبت، لذا تم حل النقطة 2.
قد يكون التعامل مع النقطة 1 صعبًا أو غير صعب. كانت النسخة 6 من تطبيقنا تعمل بدون ملفات تعريف الارتباط. من خلال دمج النسختين 2 و6، نحصل على النتيجة المطلوبة. سنضيف قيدًا إضافيًا: يجب أن يدير التطبيق جلسة عمل. هذا ليس قيدًا بلا معنى. في تطبيق يتعين على المستخدمين فيه المصادقة، يجب على الخادم حفظ زوج (المعرف / كلمة المرور) المستخدم لتجنيبه المصادقة في كل صفحة يطلبها.
استخدمنا حتى الآن ثلاثة حلول لتخزين المعلومات خلال التبادلات بين العميل والخادم:
- الجلسة
- ملفات تعريف الارتباط
- الحقول المخفية.
يمكن استبعاد الحل 2 لأن متصفح العميل قد يكون حظر استخدام ملفات تعريف الارتباط.
الحل 3 هو الحل الذي تمت دراسته سابقًا في الإصدار 6. لا يمكن استخدامه لأسباب أمنية. إذا تم تضمين الزوج (اسم المستخدم/كلمة المرور) في كل صفحة يتم إرسالها إلى المتصفح، فهذا يعني أنه يمر عبر الشبكة في كل تبادل بين العميل والخادم. وهذا ليس جيدًا لأمن التطبيق. يمكننا إذن التفكير في استخدام بروتوكول HTTPS الذي يشفر التبادلات بين العميل والخادم. لكن استخدامه لكل صفحة من صفحات التطبيق سيزيد من عبء الخادم.
قد نرغب في استبعاد الحل 1 لأنه يعتمد أيضًا على ملفات تعريف الارتباط. عند أول تبادل بين العميل والخادم، يرسل الخادم إلى العميل رمز جلسة عمل يقوم العميل بإرساله إلى الخادم في كل طلب جديد. بفضل هذا الرمز، سيتمكن الخادم من التعرف على العميل وتزويده بالمعلومات التي كان قد حفظها خلال تبادل سابق. يتم إرسال رمز الجلسة من قبل الخادم في ملف تعريف ارتباط. يمكن للمتصفح الذي لم يقم بتعطيل ملفات تعريف الارتباط أن يعيد إرسال ملف تعريف الارتباط هذا عند الطلبات التالية. إذا كان قد قام بتعطيل ملفات تعريف الارتباط، فإن هناك حلاً آخر متاحاً: يمكنه تضمين رمز الجلسة في عنوان URL الذي يطلبه. وهذا ما نراه الآن عند العودة إلى دراسة الملف [index.jsp] من الإصدار 4:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<c:redirect url="/main"/>
نذكر أن السطر 5 أعلاه يعيد توجيه العميل إلى عنوان URL [/personne4/main?jsessionid=XX] حيث XX هو رمز الجلسة كما يظهر في لقطة الشاشة أدناه التي تم الحصول عليها بعد طلب عنوان URL [http://localhost:8080/personne4]:

دعونا نلقي نظرة فاحصة على كيفية عمل العلامة <c:redirect> فيما يتعلق برمز الجلسة. لنأخذ متصفحًا يقبل ملفات تعريف الارتباط. فيما يلي، نقوم بتكوين متصفح Firefox:

في [1]، نسمح بملفات تعريف الارتباط، وفي [2] نحذف الملفات الموجودة بالفعل من أجل البدء من حالة معروفة. ثم نطلب عنوان URL [http://localhost:8080/personne4]. ونحصل على الرد التالي:

كان الطلب الأولي للعميل HTTP كما يلي:
يجب ملاحظة أن العميل لا يرسل ملف تعريف ارتباط للجلسة. الإجابة HTTP المرسلة من الخادم هي التالية:
- السطر 1: يطلب الخادم من العميل إعادة التوجيه
- السطر 3: يرسل الخادم رمز جلسة مرتبط بالسمة [JSESSIONID]
- السطر 4: يحتوي عنوان URL لإعادة التوجيه على رمز الجلسة. وقد وضعته علامة <c:redirect> هناك لأن العميل لم يرسل ملف تعريف ارتباط للجلسة.
ثم أرسل المتصفح، الذي طُلب منه إعادة التوجيه، الطلب التالي:
- السطر 1: يطلب عنوان URL لإعادة التوجيه، بما في ذلك رمز الجلسة. ولهذا السبب يعرض المتصفح عنوان URL هذا في لقطة الشاشة.
- السطر 10: يعيد المتصفح رمز الجلسة الذي أرسله إليه الخادم في التبادل السابق. هذا هو الأداء الطبيعي لملفات تعريف الارتباط عندما تكون مسموحة على متصفح العميل. إذا لم يكن الأمر كذلك، لا يتم إعادة إرسال ملفات تعريف الارتباط المستلمة.
رد الخادم بما يلي على هذا الطلب الثاني:
لقد عثر على الصفحة المطلوبة وأرسلها. تجدر الإشارة إلى أنه لم يعد يرسل رمز الجلسة. هذا هو الأداء الطبيعي لرمز الجلسة: يتم إرساله إلى المتصفح مرة واحدة فقط من قبل الخادم في شكل ملف تعريف ارتباط، ثم يعيد المتصفح إرساله مع كل طلب ليتم التعرف عليه.
الآن، باستخدام نفس المتصفح، لنطلب مرة أخرى عنوان URL [http://localhost:8080/personne4] عن طريق كتابته يدويًا. عندئذ نحصل على الصفحة التالية:

نلاحظ أن عنوان URL المعروض بواسطة المتصفح لم يعد يحتوي على رمز الجلسة. لنلقِ نظرة على التبادل الأول بين العميل والخادم:
أرسل المتصفح الطلب التالي:
وهذا هو بالضبط نفس الطلب الذي تم إرساله في المرة السابقة، ولكن مع اختلاف واحد: في السطر 10، يعيد المتصفح رمز الجلسة الذي تلقّاه خلال التبادل الأول. ومرة أخرى، هذا هو الأداء الطبيعي إذا كانت ملفات تعريف الارتباط في المتصفح نشطة.
أرسل الخادم الرد التالي:
يطلب من العميل إعادة التوجيه. ونظرًا لأنه تلقى رمز جلسة من العميل، فإنه يواصل هذه الجلسة ولا يرسل رمز جلسة جديدًا. وللسبب نفسه، لا تتضمن علامة <c:redirect> رمز الجلسة هذا في عنوان URL لإعادة التوجيه. ولهذا السبب لا يحتوي عنوان URL المعروض في لقطة الشاشة أعلاه على رمز جلسة.
سنستخلص من كل هذا القاعدة التالية: لا تضم علامة <c:redirect> رمز الجلسة في عنوان URL الخاص بإعادة التوجيه إلا إذا لم يرسل العميل الرأس HTTP:
تنطبق هذه القاعدة أيضًا على العلامة <c:url> التي سنلتقي بها لاحقًا.
ماذا يحدث مع متصفح تم تعطيل ملفات تعريف الارتباط عليه؟ لنجرب ذلك. أولاً، نقوم بإعادة تعيين المتصفح:

في [1]، نقوم بتعطيل ملفات تعريف الارتباط، وفي [2] نحذف الملفات الموجودة بالفعل من أجل البدء من حالة معروفة. ثم نطلب عنوان URL [http://localhost:8080/personne4]. ونحصل على الرد التالي:

نحصل على نفس النتيجة السابقة. ومع ذلك، فإن التبادلات HTTP ليست متطابقة تمامًا:
- الأسطر 1-9: الطلب رقم 1 من المتصفح. لا يرسل ملف تعريف ارتباط للجلسة.
- الأسطر 11-17: استجابة الخادم التي تطلب منه إعادة التوجيه إلى عنوان URL آخر. وهو يرسل ملف تعريف ارتباط للجلسة السطر 13: علامة <c:redirect> أدرجت الرمز المميز في عنوان URL لإعادة التوجيه في السطر 14.
- الأسطر 19-27: الطلب رقم 2 من المتصفح. لا يعيد ملف تعريف الارتباط الخاص بالجلسة الذي أرسله إليه الخادم للتو لأن ملفات تعريف الارتباط الخاصة به معطلة.
- الأسطر 29-33: استجابة الخادم. يمكن ملاحظة أنه على الرغم من أن المتصفح لم يرسل له ملف تعريف ارتباط الجلسة، إلا أنه لا يبدأ جلسة جديدة كما كان متوقعًا. ونلاحظ ذلك من خلال عدم إرساله لرأس HTTP [Set-Cookie] كما فعل في السطر 13. وهذا يعني أنه يواصل الجلسة السابقة. وقد تمكن من العثور عليها بفضل رمز الجلسة الموجود في عنوان URL الذي طلبه المتصفح في السطر 19.
تجدر الإشارة إلى أن الخادم يتتبع الجلسة من خلال استرداد رمز الجلسة الذي يرسله العميل، وذلك بطريقتين ممكنتين:
- في الرأس HTTP [Set-Cookie] المرسلة من العميل
- في عنوان URL الذي طلبه العميل
الآن، باستخدام نفس المتصفح، لنطلب مرة أخرى عنوان URL [http://localhost:8080/personne4] عن طريق كتابته يدويًا، كما تم فعله عندما كانت ملفات تعريف الارتباط مسموحة. عندئذ نحصل على الصفحة التالية:

لدينا نتيجة مختلفة عن تلك التي تم الحصول عليها عندما كانت ملفات تعريف الارتباط مسموحة: رمز الجلسة موجود في عنوان URL المعروض بواسطة المتصفح. دعونا نوضح هذه النتيجة دون دراسة التبادلات HTTP التي حدثت:
[cookies autorisés]
- عند الطلب الثاني لعنوان URL [http://localhost:8080/personne4]، أعاد متصفح العميل ملف تعريف الارتباط الخاص بالجلسة الذي تلقّاه من الخادم عند الطلب الأول لنفس عنوان URL. وبالتالي، لم تقم علامة <c:redirect> بتضمين رمز الجلسة في عنوان إعادة التوجيه.
[cookies inhibés]
- عند الطلب الثاني لعنوان URL [http://localhost:8080/personne4]، لا يرسل متصفح العميل ملف تعريف الارتباط الخاص بالجلسة الذي تلقّاه من الخادم عند الطلب الأول لنفس عنوان URL هذا، لأن ملفات تعريف الارتباط الخاصة به معطلة. لذلك، تضم علامة <c:redirect> رمز الجلسة في عنوان إعادة التوجيه. ولهذا السبب نجده في لقطة الشاشة أعلاه.
تسمح العلامات <c:redirect> و <c:url> بتضمين رمز الجلسة في عناوين URL. وهذا هو الحل المقترح هنا.
12.2. مشروع Eclipse
لإنشاء مشروع Eclipse [mvc-personne-07] لتطبيق الويب [/personne7]، سنقوم بنسخ مشروع [mvc-personne-06] باتباع الإجراء الموضح في الفقرة 6.2.
![]() | ![]() |
12.3. تكوين تطبيق الويب [personne7]
الملف web.xml لتطبيق /personne7 هو كما يلي:
<?xml version="1.0" encoding="UTF-8"?>
...
<display-name>mvc-personne-07</display-name>
...
هذا الملف مطابق لملف الإصدار السابق باستثناء السطر 3 حيث تغير اسم عرض تطبيق الويب إلى [mvc-personne-07]. لا تتغير الصفحة الرئيسية [index.jsp].
...
<c:redirect url="/do/formulaire"/>
12.4. رمز طرق العرض
تعود طرق العرض [formulaire, réponse, erreurs] إلى ما كانت عليه في الإصدار 2، c.a.d. بدون جافا سكريبت. ومع ذلك، فإنها تحتفظ بعلامات JSTL من الإصدارات الأخيرة.
12.4.1. طريقة العرض [formulaire]

تمت إزالة الأزرار المرتبطة برمز جافا سكريبت.
[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">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne - formulaire</title>
</head>
<body>
<center>
<h2>Personne - formulaire</h2>
<hr>
<form name="frmPersonne" action="<c:url value="validationFormulaire"/>" 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" name="bouton" value="Envoyer"></td>
<td><input type="reset" value="Rétablir"></td>
<td><input type="submit" name="bouton" value="Effacer"></td>
</tr>
</table>
</form>
</center>
</body>
</html>
- السطر 14: يتم كتابة عنوان URL الهدف لـ POST باستخدام العلامة <c:url> بحيث يكون رمز الجلسة موجودًا فيه في حالة ما إذا كان العميل متصفحًا لا يرسل رأس HTTP [Cookie].
- يحتوي النموذج على زرين من النوع [submit]: [Envoyer] (السطر 28) و [Effacer] (السطر 30). يحمل الزران نفس الاسم: bouton. عند POST، سيرسل المتصفح المعلمة:
- button=Send إذا تم إرسال POST بواسطة الزر [Send]
- button=حذف إذا تم إرسال POST بواسطة الزر [حذف]
وهذا المعامل هو الذي سيساعدنا في تحديد الإجراء المحدد الذي يجب القيام به، حيث أصبح عنوان URL [/do/validationFormulaire] يمثل الآن إجراءين منفصلين.
12.4.2. العرض [réponse]

[réponse.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">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Personne - réponse</h2>
<hr>
<table>
<tr>
<td>Nom</td>
<td>${nom}</td>
</tr>
<tr>
<td>Age</td>
<td>${age}</td>
</tr>
</table>
<br>
<a href="<c:url value="retourFormulaire"/>">${lienRetourFormulaire}</a>
</body>
</html>
- السطر 24: يتم كتابة عنوان URL الهدف لـ HREF باستخدام العلامة <c:url> بحيث يكون رمز الجلسة موجودًا فيه في حالة ما إذا كان العميل متصفحًا لا يرسل رأس HTTP [Cookie].
12.4.3. عرض [erreurs]

[erreurs.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">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<ul>
<c:forEach var="erreur" items="${erreurs}">
<li>${erreur}</li>
</c:forEach>
</ul>
<br>
<a href="<c:url value="retourFormulaire"/>">${lienRetourFormulaire}</a>
</body>
</html>
- السطر 18: يتم كتابة عنوان URL الهدف لـ HREF باستخدام العلامة <c:url> بحيث يكون رمز الجلسة موجودًا فيه في حالة ما إذا كان العميل متصفحًا لا يرسل رأس HTTP [Cookie].
يُطلب من القارئ اختبار هذه العروض الجديدة وفقًا للمبدأ الذي تمت مناقشته في الإصدارات السابقة.
12.5. وحدة التحكم [ServletPersonne]
وحدة التحكم [ServletPersonne] لتطبيق الويب [/personne7] هي كما يلي:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
- السطر 35: يتم تنفيذ الإجراء [/retourFormulaire] بواسطة GET وليس بواسطة POST كما في الإصدار السابق.
- الأسطر 70-87: يتم تنفيذ الإجراء [/validationFormulaire] بواسطة POST الذي يتم تشغيله بالنقر فوقأحد الأزرار [Envoyer] أو [Effacer] في العرض [formulaire]. تعالج الطريقة [doValidationFormulaire] هاتين الحالتين بواسطة طريقتين مختلفتين.
- الأسطر 90-103: الطريقة [doEnvoyer] تتوافق مع الطريقة [doValidationFormulaire] في الإصدار السابق. يتم وضع البيانات المدخلة في الجلسة (الأسطر 96-98) بينما في الإصدار السابق كانت توضع في الاستعلام.
- الأسطر 58-67: يجب أن تعرض الطريقة الجديدة [doEffacer] نموذجًا فارغًا. يمكننا الاستعانة بالطريقة [doInit] التي تقوم بهذه المهمة بالفعل. هنا، نستغل الفرصة أيضًا لمسح عناصر [nom, age] من الجلسة حتى تظل تعكس الحالة الأخيرة للنموذج.
- الأسطر 50-55: تطلب عرض طريقة العرض [formulaire] دون تهيئة واضحة لنموذج طريقة العرض هذه. يتكون هذا النموذج في الواقع من عناصر [nom, age] الموجودة بالفعل في الجلسة. لا داعي لفعل المزيد.
12.6. الاختبارات
قم بتشغيل أو إعادة تشغيل Tomcat بعد دمج مشروع Eclipse [personne-mvc-07] فيه، ثم اطلب عنوان URL [http://localhost:8080/personne7] باستخدام متصفح تم تعطيل ملفات تعريف الارتباط فيه وحذف الملفات الموجودة بالفعل. نحصل على الرد التالي:

الرمز المصدري الذي يتلقاه المتصفح هو التالي:
السطر 1، رمز الجلسة موجود في عنوان URL الهدف لـ POST.
لنملأ النموذج ونضغط على زر "إرسال":

الرمز المصدري الذي يتلقاه المتصفح هو التالي:
السطر 3، رمز الجلسة موجود في عنوان URL الهدف للرابط.

