Skip to content

5. تطبيق الويب MVC [personne] – الإصدار 1

5.1. طرق عرض التطبيق

يستخدم التطبيق النموذج المستخدم في الأمثلة السابقة. الصفحة الأولى للتطبيق هي التالية:

Image

سنسمي هذه الشاشة [formulaire]. إذا تم إدخال البيانات بشكل صحيح، فسيتم عرضها في شاشة ستسمى [réponse]:

Image

إذا كانت الإدخالات غير صحيحة، يتم الإبلاغ عن الأخطاء في عرض يسمى [erreurs]:

Image

5.2. بنية التطبيق

سيكون لتطبيق الويب [personne1] البنية التالية:

Image

هذه البنية هي بنية أحادية الطبقة: لا توجد طبقات [métier] أو [dao]، بل طبقة واحدة فقط هي [web]. [ServletPersonne] هو وحدة التحكم في التطبيق التي تعالج جميع طلبات العملاء. وللرد على هذه الطلبات، تستخدم إحدى العروض الثلاثة [formulaire, réponse, erreurs].

علينا تحديد كيفية قيام وحدة التحكم [ServletPersonne] بتحديد الإجراء الذي يجب القيام به عند استلام طلب من مستخدم. طلب العميل هو تدفق HTTP يختلف حسب ما إذا كان قد تم إجراؤه باستخدام الأمر GET أو POST.

الطلب GET

في هذه الحالة، يبدو التدفق HTTP كما يلي:

GET /URL HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
[ligne vide]

يحدد السطر 1 عنوان URL المطلوب، على سبيل المثال:

GET /personne1/ HTTP/1.1

يمكن استخدام عنوان URL هذا لتحديد الإجراء المطلوب. يمكن استخدام طرق مختلفة:

  1. يحدد أحد معلمات عنوان URL الإجراء، على سبيل المثال [/appli?action=ajouter&id=4]. هنا، يشير المعامل [action] إلى وحدة التحكم بالإجراء المطلوب منها.
  2. يحدد العنصر الأخير من عنوان URL الإجراء، على سبيل المثال [/appli/ajouter?id=4]. هنا، يستخدم وحدة التحكم العنصر الأخير من عنوان URL [/ajouter] لتحديد الإجراء الذي يجب القيام به.

هناك حلول أخرى ممكنة. الحلان السابقان شائعان.

الطلب POST

في هذه الحالة، يبدو التدفق HTTP كما يلي:

POST /URL HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/personne1/main
Cookie: JSESSIONID=9F5E5BFA29643FC6B1601EEED907E1F9
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
[ligne vide]
txtNom=&txtAge=&action=validationFormulaire

تحدد السطر 1 عنوان URL المطلوب، على سبيل المثال:

POST /personne1/main HTTP/1.1

يمكن استخدام عنوان URL هذا لتحديد الإجراء المطلوب كما هو الحال في GET. في حالة GET، تم دمج المعلمة [action] في URL. قد يكون هذا هو الحال هنا أيضًا كما في:

POST /appli?action=ajouter&id=4 HTTP/1.1

ولكن يمكن أيضًا تضمين المعلمة [action] في المعلمات المنشورة (السطر 15 أعلاه) كما في:

POST /appli HTTP/1.1
...
[ligne vide]
action=ajouter&id=4

فيما يلي، سنستخدم هذه التقنيات المختلفة لإرشاد وحدة التحكم إلى ما يجب عليها فعله:

  • دمج المعلمة action في عنوان URL المطلوب:
POST /appli?action=ajouter&id=4 HTTP/1.1
  • إرسال المعلمة action:
POST /appli HTTP/1.1
...
[ligne vide]
action=ajouter&id=4
  • استخدام العنصر الأخير من عنوان URL كاسم الإجراء:
POST /appli/ajouter?id=4 HTTP/1.1

5.3. مشروع Eclipse

لإنشاء مشروع Eclipse [mvc-personne-01] لتطبيق الويب [personne1]، اتبع الخطوات الموضحة في الفقرة 3.1.

Image

لن نحتفظ بالسياق [mvc-personne-01] المقترح افتراضيًا. سنختار [personne1] كما هو موضح أدناه:

Image

والنتيجة التي تم الحصول عليها هي كما يلي:

Image

إذا أردنا تغيير سياق تطبيق الويب، فسنستخدم الخيار [clic droit sur projet -> Properties -> J2EE]:

Image

سنحدد السياق الجديد في [1].

سنقوم بإنشاء مجلد فرعي [vues] داخل المجلد [WEB-INF]: [clic droit sur WEB-INF -> New -> Folder]:

المشروع الجديد هو الآن هذا:

Image

بمجرد اكتماله، سيكون المشروع كما يلي:

Image

  • المحرك [ServletPersonne] موجود في المجلد [src]
  • توجد الصفحات JSP الخاصة بعروض [formulaire, réponse, erreurs] في المجلد [WEB-INF/vues]، مما يمنع المستخدم من طلبها مباشرةً كما يوضح المثال أدناه:

Image

نصف الآن المكونات المختلفة لتطبيق الويب [/personne1]. يُطلب من القارئ إنشاؤها أثناء القراءة.

5.4. تكوين تطبيق الويب [personne1]

سيكون ملف web.xml الخاص بالتطبيق /personne1 كما يلي:


<?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-01</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>
    </servlet>
    <!--  تعيين ServletPersonne-->
    <servlet-mapping>
        <servlet-name>personne</servlet-name>
        <url-pattern>/main</url-pattern>
    </servlet-mapping>
    <!--  ملفات الصفحة الرئيسية -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

ماذا يقول ملف التكوين هذا؟

  • الأسطر 34-37: يتم معالجة URL /main بواسطة السيرفلت المسمى personne
  • الأسطر 10-13: السيرفلت المسمى personne هو مثيل لفئة [ServletPersonne]
  • الأسطر 14-19: تحدد معلمة تكوين تسمى [urlReponse]. وهي عنوان URL للطريقة [réponse].
  • الأسطر 20-25: تحدد معلمة تكوين باسم [urlErreurs]. هذا هو عنوان URL للطريقة [erreurs].
  • الأسطر 26-31: تحدد معلمة تكوين باسم [urlFormulaire]. هذا هو عنوان URL للطريقة [formulaire].
  • السطر 40: ستكون [index.jsp] هي الصفحة الرئيسية للتطبيق.

تخضع عناوين URL للصفحات JSP الخاصة بعروض [formulaire, réponse, erreurs] لمعلمة تكوين لكل منها. وهذا يسمح بنقلها دون الحاجة إلى إعادة تجميع التطبيق.

عندما يطلب المستخدم عنوان URL [/personne1]، فإن الملف [index.jsp] هو الذي سيرسل الرد (ملف الصفحة الرئيسية، السطر 40). يوجد هذا الملف في جذر المجلد [WebContent]:

Image

محتواه هو التالي:


<%@ 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("/personne1/main");
%>

تكتفي الصفحة [index.jsp] بإعادة توجيه العميل إلى عنوان URL [/personne1/main]. وبالتالي، عندما يطلب المتصفح عنوان URL [/personne1]، يرسل له [index.jsp] الرد التالي HTTP:

1
2
3
4
5
6
7
HTTP/1.x 302 Déplacé Temporairement
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=9F5E5BFA29643FC6B1601EEED907E1F9; Path=/personne1
Location: http://localhost:8080/personne1/main
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 0
Date: Thu, 18 May 2006 15:45:23 GMT
  • السطر 1: استجابة HTTP/1.1 لإرشاد الخادم إلى إعادة التوجيه إلى URL
  • السطر 4: URL الذي يجب أن يعيد توجيه المتصفح إليه

بعد هذا الرد، سيطلب المتصفح عنوان URL [/personne1/main] كما هو مطلوب منه (السطر 4). يشير الملف [web.xml] الخاص بالتطبيق [/personne1] إلى أن هذا الطلب سيتم معالجته بواسطة وحدة التحكم [ServletPersonne] (السطران 35-36).

5.5. كود العروض

نبدأ كتابة تطبيق الويب بكتابة طرق العرض الخاصة به. تسمح طرق العرض هذه بتحديد احتياجات المستخدم من حيث واجهة المستخدم الرسومية ويمكن اختبارها دون وجود وحدة التحكم.

5.5.1. الطريقة [formulaire]

هذه الواجهة هي واجهة نموذج إدخال الاسم والعمر:

Image

النوع HTML
الاسم
الدور
1
<input type= "text ">
txtNom
إدخال الاسم
2
<input type= "text ">
txtAge
إدخال العمر
3
<input type= "submit ">
 
إرسال القيم المدخلة إلى الخادم على الرابط /personne1/main
4
<input type= "reset ">
 
لإعادة الصفحة إلى الحالة التي استقبلها المتصفح بها في البداية
5
<input type= "button ">
 
لمسح محتويات حقول الإدخال [1] و [2]

يتم إنشاؤها بواسطة الصفحة JSP [formulaire.jsp]. يتكون نموذجها من العناصر التالية:

  • [nom]: اسم (String) موجود في سمات الجلسة المرتبطة بالمفتاح "name"
  • [age]: عمر (سلسلة) موجود في سمات الجلسة المرتبطة بالمفتاح "age"

يتم الحصول على العرض [formulaire] عندما يطلب المستخدم عنوان URL [/personne1/mainc.a.d. عنوان URL لوحدة التحكم [ServletPersonne]. رمز الصفحة JSP [formulaire.jsp] الذي يولد العرض [formulaire] هو التالي:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // يتم استرداد بيانات النموذج
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
    
<html>
    <head>
      <title>Personne - formulaire</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire</h2>
      <hr>
      <form 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="Envoyer"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="Effacer"></td>
          </tr>
        </table>
        <input type="hidden" name="action" value="validationFormulaire"> 
      </form>
    </center>
  </body>
</html>

  • السطران 6-7: تبدأ الصفحة JSP باسترداد العناصر [nom, age] من نموذجها في الطلب [request]. في التشغيل العادي للتطبيق، سيكون وحدة التحكم [ServletPersonne] هي التي ستقوم ببناء هذا النموذج.
  • الأسطر 18-38: ستقوم الصفحة JSP بإنشاء نموذج HTML (علامة <form>)
  • السطر 18: لا تحتوي العلامة <form> على سمة action لتعيين عنوان URL الذي سيتولى معالجة القيم المرسلة بواسطة الزر [Envoyer] من النوع submit (السطر 32). سيتم عندئذٍ إرسال قيم النموذج إلى عنوان URL الذي تم الحصول على النموذج منه، أي عنوان URL لوحدة التحكم [ServletPersonne]. وبالتالي، يتم استخدام هذا العنصر في الوقت نفسه لإنشاء النموذج الفارغ المطلوب مسبقًا بواسطة GET ومعالجة البيانات المدخلة التي سيتم إرسالها إليه باستخدام الزر [Envoyer].
  • القيم المرسلة هي قيم الحقول HTML و [txtNom] (السطر 22) و [txtAge] (السطر 26) و [action] (السطر 37). سيسمح هذا المعامل الأخير للمراقب بمعرفة ما يجب عليه فعله.
  • عند العرض الأولي للنموذج، يتم تهيئة حقول الإدخال [txtNom, txtAge] على التوالي باستخدام المتغيرات [nom] (السطر 22) و [age] (السطر 26). تحصل هذه المتغيرات على قيم سماتها من الاستعلام (السطران 6-7)، وهي سمات نعلم أنها تم تهيئتها بواسطة السيرفلت. وبالتالي، فإن السيرفلت هو الذي يحدد المحتوى الأولي لحقول الإدخال في النموذج.
  • السطر 33: يتيح الزر [Rétablir] من النوع [reset] إعادة النموذج إلى الحالة التي كان عليها عندما استلمه المتصفح.
  • السطر 34: الزر [Effacer] من النوع [reset] ليس له أي وظيفة في الوقت الحالي.

بعد ذلك، سنطلق على هذه العرض اسم العرض [formulaire(nom, age)] عندما نرغب في تحديد اسم العرض ونموذجه في آن واحد. من ناحية أخرى، تذكر أنه عندما ينقر المستخدم على الزر [Envoyer]، يتم إرسال المعلمات [txtNom, txtAge] إلى عنوان URL [/personne1/main].

5.5.2. الطريقة [reponse]

تعرض هذه العرض القيم التي تم إدخالها في النموذج عندما تكون صالحة:

Image

يتم إنشاؤها بواسطة الصفحة JSP [reponse.jsp]. يتكون نموذجها من العناصر التالية:

  • [nom]: اسم (String) سيتم العثور عليه في سمات الجلسة، مرتبط بالمفتاح "name"
  • [age]: عمر (سلسلة) سيتم العثور عليه في سمات الجلسة، مرتبط بالمفتاح "العمر"

رمز الصفحة JSP [reponse.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">
<%
    // استرداد بيانات النموذج
  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>      
  </body>
</html>

  • السطران 6-7: تبدأ الصفحة JSP باسترداد العناصر [nom, age] من نموذجها في الطلب [request]. في التشغيل العادي للتطبيق، سيكون وحدة التحكم [ServletPersonne] هي التي ستقوم ببناء هذا النموذج.
  • ثم يتم عرض عناصر [nom, age] من النموذج في السطرين 20 و 24

بعد ذلك، نسمي هذه العرض، عرض [réponse(nom, age)].

5.5.3. الطريقة [erreurs]

تشير هذه العرضة إلى أخطاء الإدخال في النموذج:

Image

يتم إنشاؤها بواسطة الصفحة JSP [erreurs.jsp]. يتكون نموذجها من العناصر التالية:

  • [erreurs]: قائمة (ArrayList) برسائل الخطأ التي ستوجد في سمات الاستعلام، مرتبطة بالمفتاح "erreurs"

رمز الصفحة JSP [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">
<%@ page import="java.util.ArrayList" %>

<%
// استرداد بيانات النموذج
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

<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>
  </body>
</html>

  • السطر 8: تبدأ الصفحة JSP باسترداد العنصر [erreurs] من نموذجها في الطلب [request]. يمثل هذا العنصر كائنًا من النوع ArrayList من عناصر من النوع String. هذه العناصر هي رسائل خطأ. في التشغيل العادي للتطبيق، سيكون المتحكم [ServletPersonne] هو الذي سيبني هذا النموذج.
  • السطور 18-22: تعرض قائمة رسائل الخطأ. ولهذا الغرض، يتعين كتابة كود Java في نص الصفحة HTML. يجب السعي دائمًا إلى تقليل هذا الكود إلى الحد الأدنى حتى لا يثقل كود HTML. سنرى لاحقًا أن هناك حلولًا تسمح بتقليل كمية كود Java في الصفحات JSP.
  • السطر 4: لاحظ علامة استيراد الحزم اللازمة للصفحة JSP

بعد ذلك، نسمي هذه العرض، عرض [erreurs(erreurs)].

5.6. اختبار العروض

من الممكن اختبار صحة الصفحات JSP دون كتابة وحدة التحكم. ولذلك، هناك شرطان:

  • يجب أن يكون من الممكن طلبها مباشرة من التطبيق دون المرور عبر وحدة التحكم
  • يجب أن تقوم الصفحة JSP بتهيئة النموذج بنفسها، والذي عادةً ما يتم إنشاؤه بواسطة وحدة التحكم

لإجراء هذه الاختبارات، نقوم بنسخ صفحات JSP الخاصة بالطرقات في مجلد [/WebContent/JSP] الخاص بمشروع Eclipse:

Image

ثم في المجلد JSP، يتم تعديل الصفحات على النحو التالي:

[formulaire.jsp]:


...

<%
  // -- اختبار: يتم إنشاء قالب الصفحة
  request.setAttribute("nom","tintin");
  request.setAttribute("age","30");
%>

<%
    // يتم استرداد بيانات النموذج
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
    
<html>
    <head>
...

تمت إضافة الأسطر 3-7 لإنشاء النموذج الذي تحتاجه الصفحة في الأسطر 11-12.

[reponse.jsp]:


...

<%
  // -- اختبار: يتم إنشاء قالب الصفحة
  request.setAttribute("nom","milou");
  request.setAttribute("age","10");
%>

<%
    // يتم استرداد بيانات النموذج
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

    
<html>
    <head>
...

تمت إضافة الأسطر 3-7 لإنشاء النموذج الذي تحتاجه الصفحة في الأسطر 11-12.

[erreurs.jsp]:


...

<%
  // -- اختبار: إنشاء قالب الصفحة
  ArrayList<String> erreurs1=new ArrayList<String>();
  erreurs1.add("erreur1");
  erreurs1.add("erreur2");
  request.setAttribute("erreurs",erreurs1);
%>

<%
// يتم استرداد بيانات النموذج
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

    
<html>
    <head>
...

تمت إضافة الأسطر 3-9 لإنشاء النموذج الذي تحتاجه الصفحة في السطر 13.

قم بتشغيل Tomcat إذا لم تكن قد قمت بذلك بالفعل، ثم اطلب العناوين التالية:

 

نحصل بالفعل على العروض المتوقعة. الآن بعد أن أصبح لدينا ثقة معقولة في صفحات JSP للتطبيق، يمكننا الانتقال إلى كتابة وحدة التحكم [ServletPersonne].

5.7. وحدة التحكم [ServletPersonne]

يبقى كتابة قلب تطبيق الويب الخاص بنا، وهو وحدة التحكم. وتتمثل مهمتها في:

  • استلام الطلب من العميل،
  • معالجة الإجراء المطلوب من قبله،
  • إرسال العرض المناسب كرد.

ستقوم وحدة التحكم [ServletPersonne] بمعالجة الإجراءات التالية:

رقم
الطلب
الأصل
المعالجة
1
[GET /personne1/main]
رابط URL الذي أدخله المستخدم
- إرسال عرض [formulaire] فارغ
2
[POST /personne1/main]
مع المعلمات [txtNom,
txtAge، الإجراء] المنشورة
النقر على الزر
[Envoyer] في العرض
[formulaire]
- التحقق من قيم المعلمات [txtNom, txtAge]
- إذا كانت غير صحيحة، إرسال العرض [erreurs(erreurs)]
- إذا كانت صحيحة، أرسل العرض [reponse(nom,age)]

يبدأ التطبيق عندما يطلب المستخدم عنوان URL [/personne1/main]. وفقًا لملف التطبيق [web.xml] (انظر الفقرة 5.4)، تتم معالجة هذا الطلب بواسطة مثيل من النوع ServletPersonne الذي سنصفه الآن.

5.7.1. هيكل وحدة التحكم

رمز وحدة التحكم [ServletPersonne] هو كما يلي:

package istia.st.servlets.personne;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
...

    // التشغيل
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
    }

    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
...
    }

    // عرض المنظر الأولي
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
...
    }

    // التحقق من صحة النموذج
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
...
    }

    // إرسال
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        // نقوم بتحويل السيطرة إلى GET
        doGet(request, response);
    }
}
  • الأسطر 20-22: الطريقة [init] التي يتم تنفيذها عند التحميل الأولي للـ servlet
  • الأسطر 25-28: الطريقة [doGet] التي يستدعيها خادم الويب عند إرسال طلب من النوع GET إلى التطبيق
  • الأسطر 42-46: يتم استدعاء الطريقة [doPost] بواسطة خادم الويب عند إرسال طلب من النوع POST إلى التطبيق. وكما هو موضح، سيتم معالجتها أيضًا بواسطة الطريقة [doGet] (السطر 45).
  • الأسطر 31-33: تعالج الطريقة [doInit] الإجراء رقم 1 [GET /personne1/main]
  • الأسطر 36-39: تعالج الطريقة [doValidationFormulaire] الإجراء رقم 2 [POST /personne1/main] باستخدام المعلمات المرسلة [txtNom, txtAge, action].

نصف الآن الطرق المختلفة لوحدة التحكم

5.7.2. تهيئة وحدة التحكم

عندما يتم تحميل فئة وحدة التحكم بواسطة حاوية السيرفلت، يتم تنفيذ طريقتها [init]. وستكون هذه المرة الوحيدة. وبمجرد تحميلها في الذاكرة، ستبقى وحدة التحكم فيها وستعالج طلبات العملاء المختلفين. يخضع كل عميل لخيط تنفيذ، وبالتالي يتم تنفيذ طرق وحدة التحكم في وقت واحد بواسطة خيوط مختلفة. تجدر الإشارة إلى أنه، لهذا السبب، يجب ألا يحتوي وحدة التحكم على حقول يمكن أن تقوم طرقها بتعديلها. يجب أن تكون حقولها للقراءة فقط. يتم تهيئتها بواسطة الطريقة [init] التي تتمثل مهمتها الرئيسية في ذلك. تتميز هذه الطريقة في الواقع بأنها تُنفذ مرة واحدة فقط بواسطة مؤشر ترابط واحد. وبالتالي، لا توجد مشاكل تتعلق بالوصول المتزامن إلى حقول وحدة التحكم في هذه الطريقة. تهدف الطريقة [init] إلى تهيئة الكائنات الضرورية لتطبيق الويب والتي سيتم مشاركتها للقراءة فقط من قبل جميع خيوط العملاء. يمكن وضع هذه الكائنات المشتركة في مكانين:

  • الحقول الخاصة لوحدة التحكم
  • سياق تنفيذ التطبيق (ServletContext)

فيما يلي كود الطريقة [init] الخاصة بوحدة التحكم [ServletPersonne]:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
    // معلمات المثيل
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

    // التشغيل
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
        // استرداد معلمات التهيئة للخدمة
        ServletConfig config = getServletConfig();
        // معالجة معلمات التهيئة الأخرى
        String valeur=null;
        for(int i=0;i<paramètres.length;i++){
            // قيمة المعلمة
            valeur=config.getInitParameter(paramètres[i]);
            // هل المعلمة موجودة؟
            if(valeur==null){
                // تسجيل الخطأ
                erreursInitialisation.add("Le paramètre ["+paramètres[i]+"] n'a pas été initialisé");
            }else{
                // يتم حفظ قيمة المعلمة
                params.put(paramètres[i],valeur);
            }
            // عنوان URL للطريقة [erreurs] له معالجة خاصة
            urlErreurs = config.getInitParameter("urlErreurs");
            if (urlErreurs == null)
                throw new ServletException(
                        "Le paramètre [urlErreurs] n'a pas été initialisé");
        }
    }
...
}
  • السطر 16: يتم استرداد تكوين تطبيق الويب، c.a.d. محتوى الملف [web.xml]
  • الأسطر 19-29 يتم استرداد معلمات التهيئة للـ servlet التي تم تعريف أسمائها في الجدول [paramètres] في السطر 9
  • السطر 21: يتم استرداد قيمة المعلمة
  • السطر 25: إذا كان المعامل غائبًا، تُضاف الخطأ إلى قائمة الأخطاء [erreursInitialisation] التي كانت فارغة في البداية (السطر 8).
  • السطر 28: إذا كان المعامل موجودًا، يتم تخزينه مع قيمته في القاموس [params] الذي كان فارغًا في البداية (السطر 10).
  • الأسطر 31-35: يجب أن يكون المعامل [urlErreurs] موجودًا بالضرورة لأنه يشير إلى عنوان URL للطريقة [erreurs] القادرة على عرض أية أخطاء في التهيئة. إذا لم يكن موجودًا، يتم إيقاف التطبيق عن طريق تشغيل [ServletException] (السطر 33).

5.7.3. الطريقة [doGet]

تعالج الطريقة [doGet] كل من الطلبات GET و POST في السيرفلت، نظرًا لأن الطريقة [doPost] تحيل إلى الطريقة [doGet]. وفيما يلي شفرة هذه الطريقة:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
    // معلمات المثيل
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

...
    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        // نتحقق من كيفية إجراء تهيئة السيرفلت
        if (erreursInitialisation.size() != 0) {
            // يتم التمرير إلى صفحة الأخطاء
            request.setAttribute("erreurs", erreursInitialisation);
            getServletContext().getRequestDispatcher(urlErreurs).forward(
                    request, response);
            // النهاية
            return;
        }

        // استرداد طريقة إرسال الطلب
        String méthode=request.getMethod().toLowerCase();
        // يتم استرداد الإجراء المطلوب تنفيذه
        String action=request.getParameter("action");
        // الإجراء؟
        if(action==null){
            action="init";
        }
        // تنفيذ الإجراء
        if(méthode.equals("get") && action.equals("init")){
            // بدء تشغيل التطبيق
            doInit(request,response);
            return;
        }
        if(méthode.equals("post") && action.equals("validationFormulaire")){
            // التحقق من صحة نموذج الإدخال
            doValidationFormulaire(request,response);
            return;
        }
        // حالات أخرى
        doInit(request,response);
    }

    // إرسال
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        // ننتقل إلى GET
        doGet(request, response);
    }
}
  • الأسطر 18-25: يتم التحقق من أن قائمة أخطاء التهيئة فارغة. إذا لم يكن الأمر كذلك، يتم عرض العرض [erreurs(erreursInitialisation)] الذي سيشير إلى الخطأ أو الأخطاء.

لفهم هذا الرمز، يجب تذكر نموذج العرض [erreurs]:

<%
// استرداد بيانات النموذج
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

تتوقع طريقة العرض [erreurs] وجود عنصر مفتاح "أخطاء" في الاستعلام. يقوم وحدة التحكم بإنشاء هذا العنصر في السطر 20.

  • السطر 28: يتم استرداد الطريقة [get] أو [post] التي استخدمها العميل لإجراء طلبه
  • السطر 30: يتم استرداد قيمة المعلمة [action] من الطلب. تجدر الإشارة إلى أنه في تطبيقنا، الطلب رقم 2 [POST /personne1/main] هو الوحيد الذي يحتوي على المعلمة [action]. في هذا الطلب، تبلغ قيمتها [validationFormulaire].
  • الأسطر 31-34: إذا لم يكن المعامل [action] موجودًا، يتم تعيين القيمة "init" له. سيكون هذا هو الحال في الطلب الأول رقم 1 [GET /personne1/main].
  • الأسطر 36-40: معالجة الطلب رقم 1 [GET /personne1/main].
  • الأسطر 41-45: معالجة الطلب رقم 2 [POST /personne1/main].
  • السطر 47: إذا لم نكن في إحدى الحالتين السابقتين، نتصرف كما لو كنا في الحالة رقم 1

5.7.4. الطريقة [doInit]

تعالج هذه الطريقة الطلب رقم 1 [GET /personne1/main]. في هذا الطلب، يجب أن ترسل العرض [formulaire(nom,age)] فارغًا. رمزها هو التالي:

package istia.st.servlets.personne;
...

@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
    // معلمات المثيل
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

...    
    // عرض الصفحة الرئيسية
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        // إرسال النموذج الفارغ
        request.setAttribute("nom", "");
        request.setAttribute("age", "");
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }
...
}
  • السطران 18-19: يتم عرض العرض [formulaire]. لنتذكر النموذج المتوقع لهذا العرض:

<%
    // استرداد بيانات النموذج
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
  • السطران 16-17: يتم تهيئة النموذج [nom,age] الخاص بالعرض [formulaire] بسلاسل فارغة.

5.7.5. الطريقة [doValidationFormulaire]

تعالج هذه الطريقة الطلب رقم 2 [POST /personne1/main] حيث المعلمات المرسلة هي [action, txtNom, txtAge]. ورمزها هو كما يلي:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
    // معلمات المثيل
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();
...
    // التحقق من صحة النموذج
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
        // استرداد المعلمات
        String nom = request.getParameter("txtNom");
        String age = request.getParameter("txtAge");
        // التحقق من المعلمات
        ArrayList<String> erreursAppel = new ArrayList<String>();
        // يجب ألا يكون الاسم فارغًا
        nom = nom.trim();
        if (nom.equals(""))
            erreursAppel.add("Le champ [nom] n'a pas été rempli");
        // يجب أن يكون العمر عددًا صحيحًا >=0
        if (!age.matches("^\\s*\\d+\\s*$"))
            erreursAppel.add("Le champ [age] est erroné");
        // هل توجد أخطاء في المعلمات؟
        if (erreursAppel.size() != 0) {
            // يتم إرسال صفحة الأخطاء
            request.setAttribute("erreurs", erreursAppel);
            getServletContext().getRequestDispatcher(urlErreurs).forward(request, response);
            return;
        }
        // المعلمات صحيحة - يتم إرسال صفحة الرد
        request.setAttribute("nom", nom);
        request.setAttribute("age", age);
        getServletContext().getRequestDispatcher((String)params.get("urlReponse")).forward(request,
                response);
        return;
    }
...
}
  • السطران 16-17: يتم استرداد قيم المعلمات "txtNom" و "txtAge" من طلب العميل.
  • السطور 19-26: يتم التحقق من صحة هذين المعلمتين
  • الأسطر 28-33: إذا كان أحد المعلمات خاطئًا، يتم عرض طريقة العرض [erreurs(erreursAppel)]. تذكر نموذج طريقة العرض هذه:

<%
// يتم استرداد بيانات النموذج
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>
  • الأسطر 35-38: إذا كانت المعلمتان "txtNom" و"txtAge" المسترجعتان تحتويان على قيم صالحة، يتم عرض العرض [reponse(nom,age)]. يجب تذكر نموذج العرض [reponse]:

<%
    // يتم استرداد البيانات من النموذج
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

5.8. الاختبارات

لنقوم بإدراج المشروع [mvc-personne-01] في تطبيقات Tomcat باتباع الإجراء الموضح في الفقرة 3.3:

Image

قم بتشغيل Tomcat. بعد ذلك، يمكننا استئناف الاختبارات الموضحة في الفقرة 5.1. ويمكننا إضافة المزيد. يمكننا على سبيل المثال حذف أحد معلمات التكوين urlXXX في web.xml ومشاهدة النتيجة. وهكذا، كما هو موضح أدناه، تم تعليق أحد المعلمات في [web.xml]:


        <!-- 
            <init-param>
              <param-name>urlFormulaire</param-name>
              <param-value>
                /WEB-INF/vues/formulaire.jsp
              </param-value>
            </init-param>
        -->

نقوم بتشغيل / إعادة تشغيل Tomcat ونطلب عنوان URL [http://localhost:8080/personne1/main]. نحصل على الرد التالي:

Image