Skip to content

5. برنامه وب MVC [personne] – نسخه ۱

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]

خط ۱ آدرس 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/person1/main
Cookie: JSESSIONID=9F5E5BFA29643FC6B1601EEED907E1F9
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
[ligne vide]
txtNom=&txtAge=&action=validationFormulaire

خط ۱ URL درخواستی را مشخص می‌کند، برای مثال:

POST /personne1/main HTTP/1.1

این URL می‌تواند برای مشخص کردن عملی که باید انجام شود، مانند مورد GET، استفاده شود. در مورد GET، پارامتر [action] در داخل URL جاسازی شده بود. این ممکن است در اینجا نیز صادق باشد، مانند:

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

با این حال، پارامتر [action] ممکن است در پارامترهای ارسال‌شده (خط ۱۵ بالا) نیز گنجانده شده باشد، به این صورت:

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 با شناسه [mvc-personne-01] برای برنامه وب [personne1]، مراحل توصیف‌شده در بخش ۳.۱ را دنبال کنید.

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 برای اپلیکیشن /person1 به شرح زیر خواهد بود:


<?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>

این فایل پیکربندی چه می‌گوید؟

  • خطوط ۳۴–۳۷: servlet با نام «person» مسئول رسیدگی به URL/main است
  • خطوط ۱۰–۱۳: سرولتی به نام «person» نمونه‌ای از کلاس [ServletPersonne] است
  • خطوط 14–19: یک پارامتر پیکربندی به نام [urlReponse] تعریف کنید. این URL نما [réponse] است.
  • خطوط ۲۰–۲۵: یک پارامتر پیکربندی به نام [urlErreurs] تعریف کنید. این URL نما [erreurs] است.
  • خطوط 26–31: یک پارامتر پیکربندی به نام [urlFormulaire] تعریف کنید. این URL برای نمای [formulaire] است.
  • خط ۴۰: [index.jsp] صفحه اصلی برنامه خواهد بود.

URLهای صفحات JSP و ویوها [formulaire, réponse, erreurs] هر یک توسط یک پارامتر پیکربندی تعریف شده‌اند. این امکان را می‌دهد که بدون نیاز به کامپایل مجدد برنامه، آن‌ها را جابجا کرد.

وقتی کاربر URL [/personne1] را درخواست می‌کند، فایل [index.jsp] پاسخ را ارسال می‌کند (فایل اصلی، خط ۴۰). این فایل در ریشه پوشه [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/person1/main
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 0
Date: Thu, 18 May 2006 15:45:23 GMT
  • خط ۱: پاسخ HTTP/1.1 برای دستور دادن به سرور جهت هدایت به URL دیگر
  • خط ۴: URL که مرورگر باید به آن هدایت شود

پس از این پاسخ، مرورگر بنابراین مطابق دستور (خط ۴) URL [/personne1/main] را درخواست خواهد کرد. فایل [web.xml] در برنامه [/personne1] مشخص می‌کند که این درخواست توسط کنترل‌کننده [ServletPersonne] (خطوط ۳۵–۳۶) پردازش خواهد شد.

5.5. کد ویو

ما نوشتن برنامه وب را با ایجاد ویوها آغاز می‌کنیم. این ویوها به ما امکان می‌دهند نیازهای کاربر را از نظر رابط گرافیکی تعریف کنیم و می‌توان آن‌ها را بدون کنترلر تست کرد.

5.5.1. ویوی [formulaire]

این نما برای فرم مورد استفاده برای وارد کردن نام و سن است:

Image

نوع HTML
نام
نقش
1
<input type="text">
txtNom
نام را وارد کنید
2
<input type="text">
txtAge
سن را وارد کنید
3
<input type="submit">
 
مقادیر وارد شده را به سرور در آدرس /person1/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>

  • خطوط ۶–۷: صفحه JSP با بازیابی عناصر [nom, age] از مدل خود در درخواست [request] آغاز می‌شود. در حین عملکرد عادی برنامه، کنترلر [ServletPersonne] این قالب را ایجاد خواهد کرد.
  • خطوط ۱۸–۳۸: صفحه JSP یک فرم HTML (برچسب <form>) تولید خواهد کرد.
  • خط ۱۸: تگ <form> دارای ویژگی action برای مشخص کردن URL‌ای که مقادیر ارسال‌شده توسط دکمه [Envoyer] از نوع submit (خط ۳۲) را پردازش می‌کند، نیست. سپس مقادیر فرم به URL‌ای که فرم از آن دریافت شده است ارسال می‌شوند، یعنی URL کنترل‌کننده [ServletPersonne]. بنابراین، این کنترل‌کننده هم برای تولید فرم خالی که در ابتدا توسط GET درخواست شده است، و هم برای پردازش داده‌های وارد شده که از طریق دکمه [Envoyer] به آن ارسال می‌شود، استفاده می‌شود.
  • مقادیر ارسال‌شده، مقادیر فیلدهای HTML، [txtNom] (خط ۲۲)، [txtAge] (خط ۲۶) و [action] (خط ۳۷) هستند. این پارامتر نهایی به کنترل‌کننده امکان می‌دهد تا اقدام مناسب را تعیین کند.
  • هنگامی که فرم برای اولین بار نمایش داده می‌شود، فیلدهای ورودی [txtNom, txtAge] به ترتیب با متغیرهای [nom] (خط ۲۲) و [age] (خط ۲۶) مقداردهی اولیه می‌شوند. این متغیرها مقادیر ویژگی‌های خود را از درخواست (خطوط ۶–۷) دریافت می‌کنند، ویژگی‌هایی که می‌دانیم توسط سرولت مقداردهی شده‌اند. بنابراین این سرولت است که محتوای اولیهٔ فیلدهای ورودی فرم را تعیین می‌کند.
  • خط ۳۳: دکمه [Rétablir]، از نوع [reset]، فرم را به حالتی که هنگام دریافت آن توسط مرورگر داشت، بازمی‌گرداند.
  • خط ۳۴: دکمه [Effacer]، از نوع [reset]، در حال حاضر فاقد عملکرد است.

از این پس، هرگاه بخواهیم هم نام نما و هم قالب آن را مشخص کنیم، به این نما «[formulaire(nom, age)]» خواهیم گفت. علاوه بر این، باید توجه داشت که وقتی کاربر روی دکمه [Envoyer] کلیک می‌کند، پارامترهای [txtNom, txtAge] به URL [/personne1/main] ارسال می‌شوند.

5.5.2. نما [reponse]

این نما مقادیر وارد شده در فرم را در صورت معتبر بودن نمایش می‌دهد:

Image

این توسط صفحه JSP [reponse.jsp] تولید می‌شود. قالب آن شامل عناصر زیر است:

  • [nom]: یک نام (String) که در ویژگی‌های جلسه یافت می‌شود و با کلید "name" مرتبط است
  • [age]: یک سن (رشته) که در ویژگی‌های جلسه یافت می‌شود و با کلید "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>

  • خطوط ۶–۷: صفحه JSP با بازیابی عناصر [nom, age] از مدل خود در درخواست [request] آغاز می‌شود. در جریان عملکرد عادی برنامه، کنترل‌کننده [ServletPersonne] این قالب را می‌سازد.
  • سپس عناصر [nom, age] مدل در خطوط ۲۰ و ۲۴ نمایش داده می‌شوند.

ما به این نما، نمای [réponse(nom, age)] خواهیم گفت.

5.5.3. نما [erreurs]

این نما خطاهای ورودی را به شکل زیر نشان می‌دهد:

Image

این توسط صفحه JSP [erreurs.jsp] تولید می‌شود. قالب آن شامل عناصر زیر است:

  • [erreurs]: یک لیست (ArrayList) از پیام‌های خطا یافت‌شده در ویژگی‌های درخواست، مرتبط با کلید "errors"

کد صفحه 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");
        }//برای
      %>
    </ul>
  </body>
</html>

  • خط ۸: صفحه JSP با بازیابی عنصر [erreurs] از قالب خود در درخواست [request] آغاز می‌شود. این عنصر نمایانگر یک شی از نوع ArrayList است که شامل عناصری از نوع String می‌باشد. این عناصر پیام‌های خطا هستند. در حین عملکرد عادی برنامه، کنترل‌کننده [ServletPersonne] این مدل را ایجاد خواهد کرد.
  • خطوط ۱۸–۲۲: نمایش لیست پیام‌های خطا. برای این کار، باید کد جاوا را در بدنه صفحه HTML بنویسیم. همیشه باید سعی کنیم این مقدار را به حداقل برسانیم تا کد HTML شلوغ نشود. بعداً خواهیم دید که راه‌حل‌هایی برای کاهش حجم کد جاوا در صفحات JSP وجود دارد.
  • خط ۴: به عبارت import برای پکیج‌های مورد نیاز صفحه 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>
...

خطوط ۳ تا ۷ برای ایجاد قالب مورد نیاز صفحه در خطوط ۱۱ تا ۱۲ اضافه شده‌اند.

[reponse.jsp]:


...

<%
  //-- تست: ایجاد قالب صفحه
  request.setAttribute("nom","milou");
  request.setAttribute("age","10");
%>

<%
    //داده‌ها را از قالب بازیابی می‌کند
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

    
<html>
    <head>
...

خطوط ۳–۷ برای ایجاد قالب مورد نیاز صفحه در خطوط ۱۱–۱۲ اضافه شده‌اند.

[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>
...

خطوط ۳–۹ برای ایجاد قالب مورد نیاز خط ۱۳ صفحه اضافه شده‌اند.

اگر هنوز تام‌کت را راه‌اندازی نکرده‌اید، آن را راه‌اندازی کنید، سپس آدرس‌های URL زیر را درخواست کنید:

 

ما واقعاً نماهای مورد انتظار را دریافت می‌کنیم. اکنون که اطمینان معقولی به صفحات JSP برنامه داریم، می‌توانیم به نوشتن کنترلر آن، [ServletPersonne]، بپردازیم.

5.7. کنترلر [ServletPersonne]

تنها کاری که باقی مانده نوشتن هستهٔ برنامهٔ وب ما است: کنترلر. نقش آن این است که:

  • بازیابی درخواست مشتری،
  • پردازش عملی که توسط مشتری درخواست شده است،
  • بازگرداندن نمای مناسب در پاسخ.

کنترل‌کننده [ServletPersonne] اقدامات زیر را مدیریت خواهد کرد:

خیر.
درخواست
مبدأ
پردازش
۱
[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 {
...

     //init
    @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);
    }
}
  • خطوط ۲۰–۲۲: متد [init] که هنگام بارگذاری اولیه سرولت اجرا می‌شود
  • خطوط ۲۵–۲۸: متد [doGet] که توسط وب سرور زمانی که درخواستی از نوع GET به برنامه ارسال می‌شود، فراخوانی می‌شود
  • خطوط ۴۲–۴۶: متد [doPost] توسط وب‌سرور فراخوانی می‌شود زمانی که درخواستی از نوع POST به برنامه ارسال می‌شود. همان‌طور که نشان داده شده است، این مورد نیز توسط متد [doGet] (خط ۴۵) رسیدگی خواهد شد.
  • خطوط 31–33: متد [doInit] اقدام شماره 1، [GET /personne1/main] را مدیریت می‌کند
  • خطوط ۳۶–۳۹: متد [doValidationFormulaire] اقدام شمارهٔ ۲، [POST /personne1/main]، را با پارامترهای ارسال‌شدهٔ [txtNom, txtAge, action] پردازش می‌کند.

اکنون روش‌های مختلف کنترل‌کننده را شرح خواهیم داد

5.7.2. ابتدایی‌سازی کنترل‌کننده

هنگامی که کلاس کنترل‌کننده توسط کانتینر سرولت بارگذاری می‌شود، متد [init] آن اجرا می‌گردد. این تنها یک بار اتفاق می‌افتد. پس از بارگذاری در حافظه، کنترل‌کننده در آنجا باقی می‌ماند و درخواست‌های مشتریان مختلف را پردازش می‌کند. هر کلاینت توسط یک نخ اجرایی مجزا پردازش می‌شود و بنابراین متدهای کنترل‌کننده به طور همزمان توسط نخ‌های مختلف اجرا می‌شوند. توجه داشته باشید که به همین دلیل، کنترلر نباید هیچ فیلدی داشته باشد که متدهای آن بتوانند آن را تغییر دهند. فیلدهای آن باید فقط-خواندنی (read-only) باشند. این فیلدها توسط متد [init] که هدف اصلی آن است، مقداردهی اولیه می‌شوند. این متد از این جهت منحصر به فرد است که تنها یک بار توسط یک تاند (thread) واحد اجرا می‌شود. بنابراین در این متد هیچ مشکلی در دسترسی همزمان به فیلدهای کنترلر وجود ندارد. هدف متد [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é");
        }
    }
...
}
  • خط ۱۶: پیکربندی برنامه وب، c.a.d، بازیابی می‌شود. محتویات فایل [web.xml]
  • خطوط ۱۹–۲۹: پارامترهای راه‌اندازی سرولت بازیابی می‌شوند؛ نام‌های آن‌ها در جدول [paramètres] در خط ۹ تعریف شده‌اند
  • خط ۲۱: مقدار پارامتر بازیابی می‌شود
  • خط ۲۵: اگر پارامتر وجود نداشته باشد، خطا به لیست خطاهای [erreursInitialisation] اضافه می‌شود که در ابتدا خالی است (خط ۸).
  • خط ۲۸: اگر پارامتر موجود باشد، همراه با مقدار خود در دیکشنری [params] ذخیره می‌شود که در ابتدا خالی است (خط ۱۰).
  • خطوط ۳۱–۳۵: پارامتر [urlErreurs] باید موجود باشد، زیرا URL نمای [erreurs] را مشخص می‌کند که قادر به نمایش هرگونه خطای راه‌اندازی است. اگر این متد وجود نداشته باشد، برنامه با راه‌اندازی [ServletException] (خط ۳۳) خاتمه می‌یابد.

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 {

         // ما بررسی می‌کنیم که inicialization سرولت چگونه انجام شد
        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);
    }
}
  • خطوط ۱۸–۲۵: سیستم بررسی می‌کند که آیا لیست خطاهای инициализация خالی است یا خیر. اگر اینطور نباشد، نمای [erreurs(erreursInitialisation)] را نمایش می‌دهد که خطا(ها) را گزارش خواهد کرد.

برای درک این کد، باید قالب نما [erreurs] را به یاد بیاورید:

<%
//بازیابی داده‌ها از مدل
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

ویو [erreurs] انتظار یک عنصر کلیدی «errors» را در درخواست دارد. کنترلر این عنصر را در خط ۲۰ ایجاد می‌کند.

  • خط ۲۸: متد [get] یا [post] که توسط کلاینت برای ارسال درخواست خود استفاده می‌شود، بازیابی می‌شود
  • خط ۳۰: مقدار پارامتر [action] در درخواست بازیابی می‌شود. به یاد داشته باشید که در برنامه ما، تنها درخواست شماره 2 ([POST /personne1/main]) دارای پارامتر [action] است. در این درخواست، مقدار آن [validationFormulaire] است.
  • خطوط ۳۱–۳۴: اگر پارامتر [action] موجود نباشد، مقدار «init» به آن اختصاص داده می‌شود. این مورد برای درخواست اولیه شماره ۱، [GET /personne1/main]، صدق می‌کند.
  • خطوط ۳۶–۴۰: پردازش درخواست شماره ۱، [GET /personne1/main].
  • خطوط ۴۱–۴۵: پردازش درخواست شماره ۲ [POST /personne1/main].
  • خط ۴۷: اگر هیچ‌یک از دو حالت قبلی اعمال نشود، فرض کنید حالت شماره ۱ اعمال شده است

5.7.4. روش [doInit]

این روش درخواست شمارهٔ ۱ [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;
    }
...
}
  • خطوط ۱۸–۱۹: نمای [formulaire] نمایش داده می‌شود. بیایید قالب مورد انتظار این نما را به یاد بیاوریم:

<%
    // استخراج داده‌ها از مدل
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
  • خطوط 16–17: قالب [nom,age] برای نما [formulaire] با رشته‌های خالی مقداردهی اولیه می‌شود.

5.7.5. روش [doValidationFormulaire]

این متد درخواست شمارهٔ ۲، [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;
    }
...
}
  • خطوط ۱۶–۱۷: مقادیر پارامترهای «txtNom» و «txtAge» از درخواست کلاینت بازیابی می‌شوند.
  • خطوط ۱۹–۲۶: اعتبار این دو پارامتر بررسی می‌شود
  • خطوط ۲۸–۳۳: اگر هر یک از پارامترها نادرست باشد، نما [erreurs(erreursAppel)] نمایش داده می‌شود. قالب این نما را به یاد بیاورید:

<%
// استخراج داده‌ها از قالب
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>
  • خطوط ۳۵–۳۸: اگر دو پارامتر «txtNom» و «txtAge» که بازیابی شده‌اند مقادیر معتبر داشته باشند، نمای [reponse(nom,age)] نمایش داده می‌شود. قالب نما [reponse] را به خاطر بسپارید:

<%
    // استخراج داده‌ها از مدل
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

5.8. Tests

بیایید پروژه [mvc-personne-01] را با دنبال کردن رویه‌ای که در بخش ۳.۳ شرح داده شده است، در برنامه‌های Tomcat وارد کنیم:

Image

تامکت را راه‌اندازی کنید. پس از انجام این کار، می‌توانیم آزمایش‌های نشان‌داده‌شده به‌عنوان مثال در بخش 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>
        -->

ما تام‌کت را راه‌اندازی یا مجدداً راه‌اندازی می‌کنیم و URL [http://localhost:8080/personne1/main] را درخواست می‌کنیم. پاسخ زیر را دریافت می‌کنیم:

Image