Skip to content

2. مثال أول

ستقتصر معظم أمثلةنا على الطبقة الويب التي تم تنفيذها باستخدام Struts 2:

وبمجرد إتقان الأساسيات، سندرس مثالًا أكثر تعقيدًا باستخدام بنية متعددة الطبقات.

2.1. إنشاء المثال

نقوم بإنشاء تطبيقنا الأول.

  • في [1]، نقوم بإنشاء مشروع جديد
  • في [2]، نختار نوع Java Web / Web Application
  • في [3]، نسمي المشروع
  • في [4]، نحدد موقع المشروع.
  • في [5]، نجعل المشروع الجديد هو المشروع الرئيسي.
  • في [6]، نختار خادم Tomcat. عند تثبيت NetBeans 7.01، تم تثبيت خادمين، هما Apache Tomcat و Glassfish 3.1.
  • في [7]، نحدد أننا سنعمل باستخدام إطار العمل Struts 2. إن تثبيت المكون الإضافي لـ Struts 2 هو ما يتيح لنا هذه الإمكانية. فبدون هذا المكون الإضافي، لن يتم عرض إطار العمل Struts 2 علينا.
  • في [8]، يُطلب إنشاء مشروع المثال الذي سنقوم بدراسته.
  • في [9]، يمكننا التحقق من مكتبات Struts 2 التي سيتم استخدامها.
  • في [10]، المشروع الذي تم إنشاؤه. سنعود إليه لاحقًا.
  • في [11]، مكتبات المشروع. تم دمجها بواسطة المكون الإضافي Struts 2. إذا لم يكن المكون الإضافي متاحًا، فيمكن العثور على هذه المكتبات في المجلد [lib] ضمن حزمة Struts 2 التي تم تنزيلها. عندئذٍ سنقوم باتباع الخطوتين 12 و13.

2.2. المشروع الذي تم إنشاؤه في نظام الملفات

  • في [1]، تعرض علامة التبويب [Projects] عرضًا «للمطور» للمشروع
  • في [2]، تعرض علامة التبويب [Files] مجلد المشروع في نظام الملفات
  • في [2A]، يتم تمثيل الفرع [Web Pages] في [2] من خلال المجلد [web] [2B]
  • في [3A]، يتم تمثيل الفرع [Source Packages] في [2] بواسطة المجلد [java] [3B]

2.3. ملف التكوين [META-INF/context.xml]

هذا الملف هو التالي:


<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/exemple-01"/>

تشير السطر 2 إلى أن سياق تطبيق الويب هو /exemple-01. سيتم معالجة جميع عناوين URL من النوع [http://machine:port/exemple-01/...] بواسطة هذا التطبيق. يمكن العثور على هذا السياق في خصائص المشروع [2]: انقر بزر الماوس الأيمن على المشروع / Properties / Run.

2.4. ملف التكوين [WEB-INF/web.xml]

يتم تكوين أي تطبيق ويب بواسطة الملف [web.xml] الموجود في المجلد [WEB-INF] الخاص بالتطبيق. الملف الذي تم إنشاؤه هو التالي:


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>example/HelloWorld.jsp</welcome-file>
    </welcome-file-list>
</web-app>
  • تحدد الأسطر 3-6 مرشحًا تم تنفيذه بواسطة الفئة [org.apache.struts2.dispatcher.FilterDispatcher] في Struts 2. وهذه الفئة هي التي ستؤدي دور وحدة التحكم C للنموذج MVC.
  • الأسطر 7-10: تحدد ارتباطًا بين نموذج URL والمرشح الذي يجب أن يعالج عناوين URL التي تتبع هذا النموذج. هنا، يُشار إلى أن أي عنوان URL (النمط /*) يجب أن تتم معالجته بواسطة المرشح المسمى struts2. وهو المرشح المُعرَّف في الأسطر 3-6. وبالتالي، ستمر جميع عناوين URL هنا عبر وحدة التحكم Struts 2.
  • الأسطر 11-15: تحدد مدة جلسة المستخدم، وهي هنا 30 دقيقة. عند إرسال الطلبات المختلفة، يتم تتبع المستخدم بواسطة رمز جلسة تم تخصيصه له عند طلبه الأول، ويقوم بعد ذلك بإرساله بشكل منهجي مع كل طلب جديد. وهذا يسمح لخادم الويب بالتعرف عليه وإدارة «ذاكرة» للمستخدم تُسمى الجلسة. إذا مر أكثر من 30 دقيقة بين طلبين، يتم إنشاء رمز جلسة جديد للمستخدم الذي يفقد بذلك «ذاكرته» ويبدأ بواحدة جديدة.
  • الأسطر 16-18: تحدد الملف الذي سيتم عرضه عندما يستعلم المستخدم عن تطبيق الويب دون طلب مستند. وبالتالي، عندما يكون عنوان URL المطلوب هو [http://machine:port/exemple-01]، فإن عنوان URL الذي سيتم تقديمه سيكون [http://machine:port/exemple-01/example/HelloWord.jsp].

2.5. ملف التكوين [struts.xml]

الملف [struts.xml] هو ملف تكوين Struts 2. ويمكن أن يكون موجودًا في أي مكان ضمن مجلد ClassPath الخاص بالمشروع. في مشروع NetBeans أعلاه، يتكون مجلد ClassPath الخاص بالمشروع من فرعين:

  • حزم المصادر
  • المكتبات

وبالتالي، فإن أي مجلد أو مكتبة موجودة في هذين الفرعين تُعد جزءًا من ملف ClassPath الخاص بالمشروع. ومن المعتاد وضع ملف [struts.xml] في <default package>. وفي هذه الحالة، يكون محتواه كما يلي:


<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <include file="example.xml"/>
    <!-- تكوين الحزمة الافتراضية. -->
    <package name="default" extends="struts-default">
    </package>
</struts>
  • السطران 5 و10: العلامة الجذرية للمستند هي العلامة <struts>
  • السطر 6: يتم إدراج الملف [example.xml] هنا. وبالتالي، فإنه يجلب تكوينه الخاص. سنعود إلى هذا لاحقًا.
  • السطران 8-9: يحددان حزمة تُسمى هنا «default». تسمح الحزمة بتكوين مجموعة من إجراءات Struts 2 التي لها نفس عنوان URL. على سبيل المثال، [/chemin/Action1] و[/chemin/Action2]. يمكن عندئذٍ تعريف حزمة لهذه الإجراءات:

<package name="employes" namespace="/employes" extends="struts-default">
... configuration
    </package>

يُسمى الحزمة المذكورة أعلاه "employes" وتقوم بتكوين إجراءات URL /employes/Action. يمكن أن ترث الحزمة حزمة أخرى باستخدام الكلمة الرئيسية "extends". في المثال أعلاه، ترث الحزمة employes الحزمة struts-default. توجد هذه الحزمة في الملف [struts-default.xml] ضمن المكتبة struts2-core.jar:

تقوم الحزمة "struts-default" المُعرَّفة في الملف [struts-default.xml] بتكوين عناصر متنوعة، من بينها قائمة بالمعترضات التي يتم تنفيذها عند استدعاء إجراء ما. لنعد إلى بنية MVC لتطبيق Struts 2:

لمعالجة عنوان URL بالصيغة [http://machine:port/.../Action]، سيقوم وحدة التحكم [FilterDispatcher] بإنشاء مثيل للفئة التي تنفذ الإجراء المطلوب، ثم تنفيذ إحدى طرقها، وهي طريقة تُسمى execute بشكل افتراضي. وسيخضع استدعاء هذه الطريقة execute لسلسلة من المعترضات:

تقوم كل من المعترضات والإجراء بمعالجة نفس الطلب. قائمة المعترضات المحددة في الحزمة struts-default كافية في معظم الأحيان. ولذلك، ستقوم حزم Struts الخاصة بنا دائمًا بتوسيع الحزمة struts-default. لمعرفة وظائف المعترضات المختلفة، يمكن الرجوع إلى الفصل 4 من [ref2].

لنعد إلى ملف التكوين struts.xml:


<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <include file="example.xml"/>
    <!-- تكوين الحزمة الافتراضية. -->
    <package name="default" extends="struts-default">
    </package>
</struts>
  • السطر 8: الحزمة المسماة default لها دور خاص. فهي تعالج الإجراءات التي لم يتم تكوينها في الحزم الأخرى. هنا، في السطرين 8-9، لم يتم إجراء أي تكوين للحزمة default. لذا يمكن حذف تعريف هذه الحزمة.

لنلقِ نظرة الآن على الملف [example.xml] المُدرج في السطر 6 من الملف [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>
    <package name="example" namespace="/example" extends="struts-default">
        <action name="HelloWorld" class="example.HelloWorld">
            <result>/example/HelloWorld.jsp</result>
        </action>
    </package>
</struts>
  • السطر 8: يُعرّف حزمة باسم example تُوسّع نطاق الحزمة struts-default. تتولى هذه الحزمة إدارة عناوين URL من النوع /example/Action (مساحة الاسم /example).
  • الأسطر 9-11: تحدد إجراءً باسم HelloWorld (السمة name) والذي يتوافق بالتالي مع عنوان URL /example/Helloworld. تتم معالجة هذا الإجراء بواسطة مثيل للفئة example.HelloWorld (السمة class).
  • وسيقوم المتحكم [FilterDispatcher] بتنفيذ الطريقة execute الخاصة بهذه الفئة.
  • وستُرجع هذه الطريقة سلسلة أحرف تُسمى «مفتاح التنقل».
  • يجب تعريف مفاتيح التنقل المختلفة باستخدام علامات <result name="مفتاح"/> (السطر 10). في حالة عدم وجود السمة name، يتم استخدام المفتاح success افتراضيًا. وهذا هو الحال في المثال أعلاه. لذلك، يجب أن تقوم الطريقة execute التابعة للفئة example.HelloWorld بإرجاع المفتاح success إلى وحدة التحكم [FilterDispatcher].
  • ثم يقوم عنصر التحكم [FilterDispatcher] بعرض الصفحة [/example/HelloWorld.jsp] (السطر 10).

إذا قمنا بدمج الملفين [struts.xml] و [example.xml]، وحذفنا الحزمة default التي تبدو غير ضرورية، فسيكون الأمر كما لو أن الملف [struts.xml] قد تم اختزاله إلى الملف [example.xml] وحده.

2.6. الإجراء HelloWorld

وفقًا للملف [struts.xml] الذي تمت دراسته، يتم تشغيل الإجراء HelloWorld عندما يكون عنوان URL المطلوب من قبل العميل هو /example/HelloWorld. وعندها يتم تنفيذ طريقتها execute. ويجب أن تُرجع مفتاح التنقل. وقد رأينا أنه لا يوجد سوى مفتاح واحد: success، وبالتالي كانت الصفحة /example/HelloWorld.jsp هي التي تم إرسالها استجابةً للمستخدم.

فيما يلي كود الإجراء HelloWorld:


package example;

import com.opensymphony.xwork2.ActionSupport;

public class HelloWorld extends ActionSupport {

    public String execute() throws Exception {
        setMessage(getText(MESSAGE));
        return SUCCESS;
    }

    public static final String MESSAGE = "HelloWorld.message";

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
  • السطر 5: الفئة HelloWorld مشتقة من الفئة ActionSupport في Struts 2. وهذا هو الحال دائمًا تقريبًا. ويتيح ذلك الاستفادة من بعض الطرق مثل الطريقة getText الواردة في السطر 8.
  • الأسطر 7-10: الطريقة execute التي يتم تنفيذها عند استدعاء وحدة التحكم Struts. من المعروف أنها يجب أن تُرجع سلسلة أحرف، ومن هنا تأتي توقيعها في السطر 7. وهنا ستُرجع الثابت SUCCESS المُعرَّف أيضًا في ActionSupport. وهكذا يتم تعريف ثوابت أخرى لنتيجة الطريقة execute:
Constante
Valeur
SUCCESS
"success"
ERROR
"error"
INPUT
"input"
LOGIN
"login"

إذن، في هذه الحالة، تُنتج الطريقة execute السلسلة success. وإذا ما أشرنا إلى الملف [struts.xml]، فستكون الصفحة /example/HelloWorld.jsp هي التي سيتم إرجاعها كاستجابة للمستخدم.

  • السطر 8: تقوم الطريقة execute بتهيئة الحقل message في السطر 14 بقيمة getText(" HelloWorld.message "). تنتمي الطريقة getText إلى الفئة الأم ActionSupport. وهي تسمح باسترداد نص من ملف وفقًا للغة المستخدمة. بشكل افتراضي، سيتم هنا استخدام الملف package.properties الموجود في نفس الحزمة التي توجد بها الإجراء. ويأتي هذا الملف في نسختين:

الملف [package.properties] هو كما يلي:

HelloWorld.message= Struts is up and running ...

وهو عبارة عن سلسلة من أسطر النص بالصيغة clé=valeur. إذا تم استخدام هذا الملف، فستكون قيمة getText("HelloWorld.message") هي Struts is up and running ...

أما الملف [package_es.properties] فهو كما يلي:

HelloWorld.message= ¡Struts está bien! ...

إذا كانت اللغة المستخدمة من قبل متصفح العميل هي الإسبانية (السمة es، في package_es.properties)، فستكون قيمة getText("HelloWorld.message") هي ¡Struts está bien! ... وفي جميع الحالات الأخرى، سيتم استخدام الملف [package.properties].

2.7. الطريقة HelloWorld.jsp

هذا هو العنصر الأخير في أحجية Struts. إنه العرض الذي يظهر عند طلب عنوان URL /example/HelloWorld. لقد رأينا المسار المعقد الذي مر به الطلب الأولي حتى يتم عرض هذا الرد في النهاية. كود الصفحة هو كما يلي:


<%@ page contentType="text/html; charset=UTF-8" %>

<%@ taglib prefix="s" uri="/struts-tags" %>

<html>
    <head>
        <title><s:text name="HelloWorld.message"/></title>
    </head>

    <body>
        <h2><s:property value="message"/></h2>

        <h3>Languages</h3>
        <ul>
            <li>
                <s:url id="url" action="HelloWorld">
                    <s:param name="request_locale">en</s:param>
                </s:url>
                <s:a href="%{url}">English</s:a>
            </li>

            <li>
                <s:url id="url" action="HelloWorld">
                    <s:param name="request_locale">es</s:param>
                </s:url>

                <s:a href="%{url}">Espanol</s:a>

            </li>
        </ul>
    </body>
</html>
  • تستخدم الصفحة علامات HTML (الأسطر 5 و6 و...) وعلامات من مكتبة محددة في السطر 3. تنتمي جميع العلامات <s:xx> إلى هذه المكتبة.
  • السطر 7: تسمح علامة <s:text> بعرض نص مختلف وفقًا للغة متصفح العميل. يشير السمة name إلى المفتاح الذي يجب البحث عنه في ملفات الرسائل. هنا أيضًا، سيتم استخدام ملفات package_xx.properties. نتذكر أنها لا تحتوي إلا على رسالة واحدة بمفتاح HelloWorld.message.
  • السطر 11: تسمح العلامة <s:property name="propriété"> بكتابة قيمة إحدى خصائص كائن يُسمى ActionContext. ويوجد في هذا الكائن:
  • خصائص الإجراء الذي تم تنفيذه. ستعرض name="message" قيمة حقل message الخاص بالإجراء الحالي. تُستخدم الطرق get و set المرتبطة بالحقل للحصول على قيمته أو تهيئته. لذا يجب أن تكون هذه الطرق موجودة.
  • سمات الطلب الحالي المشار إليها بـ <s:property name="#request['clé']">
  • سمات جلسة عمل المستخدم المشار إليها بـ <s:property name="#session['clé']">
  • سمات التطبيق نفسه المشار إليها بـ <s:property name="#application['clé']">
  • المعلمات المرسلة من متصفح العميل والمشار إليها بـ <s:property name="#parameters['clé']">
  • الترميز <s:property name="#attr['clé']"> يعرض قيمة كائن يتم البحث عنه في الصفحة، ثم في الاستعلام، ثم في الجلسة، ثم في التطبيق، بهذا الترتيب.
  • الأسطر 16-18: تُستخدم العلامة <s:url> لتعريف عنوان URL. يحدد السمة id اسمًا لعنوان URL الذي سيتم إنشاؤه. ويُستخدم هذا الاسم لاحقًا في السطر 19. تشير السمة action إلى الإجراء الذي يجب أن يشير إليه عنوان URL.
  • السطر 17: تسمح العلامة <s:param ..> بإضافة معلمات إلى عنوان URL بالصيغة ?param1=valeur1&param2=valeur2&.... هنا، ستكون المعلمة المضافة هي ?request_locale=es.

وفي النهاية، سيكون عنوان URL الذي تم إنشاؤه كما يلي:

لفهم عنوان URL هذا، يجب أن نتذكر أن الصفحة [HelloWorld.jsp] تُعرض في حالتين:

  • عند الطلب المباشر لعنوان URL [/exemple-01/example/HelloWorld.jsp]
  • عند طلب الإجراء [/exemple-01/example/HelloWorld.action]

في كلتا الحالتين، يكون مسار عنوان URL هو /exemple-01/example.. وتقوم العلامة <s:url action= "... "> بإضافة الإجراء المحدد بواسطة السمة action إلى هذا المسار. وبذلك نحصل على /example-01/example/HelloWorld. ثم تضيف اللاحقة .action إلى عنوان URL السابق بالإضافة إلى معلمات عنوان URL إن وجدت. وعنوان URL الناتج /example-01/example/HelloWorld.action?request_locale=en ستستدعي الإجراء HelloWorld المُعرَّف في الملف [struts.xml] مع تمرير المعلمة request_locale=en. ولن تتم معالجة هذا المعلمة بواسطة الإجراء HelloWorld بل بواسطة أحد اعتراضات Struts، وهو الذي يدير تدويل الصفحات. سيتم التعرف على المعلمة request_locale ومعالجتها. وستصبح لغة الصفحات هي الإنجليزية (en).

  • السطر 19: يحدد رابط HTML. يتوقع السمة href لعلامة <a> سلسلة أحرف. هنا، نريد استخدام قيمة عنوان URL المحددة في السطر 16 والتي تحمل المعرف url. ولذلك نكتب href="%{url}". يتم تقييم المتغير url وتعيين قيمته إلى السمة href. في معظم الحالات، يكون تقييم المتغيرات ضمنيًا. على سبيل المثال، عند كتابة

<s:property name= "message "/>

يتم عرض قيمة الخاصية message وليس السلسلة "message". ولكن في حالات أخرى، يجب فرض تقييم المتغيرات أو الخصائص. لو كنا قد كتبنا href= "url"، لكان السلسلة url هي التي عُينت للسمة href.

  • الأسطر 23-27: تُنشئ رابطًا HTML لتغيير لغة الصفحات إلى الإسبانية.

2.8. تشغيل التطبيق

نبدأ تشغيل المشروع:

  • في [1]، يتم تشغيل المشروع [exemple-01]. عندها يتم تشغيل خادم الويب Tomcat تلقائيًا إذا لم يكن قد تم تشغيله بالفعل. يتم طلب عنوان URL [/exemple-01] [3]. عندها يتم استخدام الملف [web.xml]:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>example/HelloWorld.jsp</welcome-file>
    </welcome-file-list>
</web-app>
  • لأنه في عنوان URL المطلوب [/exemple-01]، لم يتم تحديد أي صفحة، سيستخدم Tomcat العلامة <welcome_file-list> الموجودة في السطرين 16 و18. وبالتالي، سيتم عرض عنوان URL /exemple-01/example/HelloWorld.jsp.
  • ونظرًا لأن Struts 2 يعالج جميع عناوين URL (السطران 8 و9)، فسيتم تصفية هذا الرابط بواسطة Struts. وبما أنه لا يتطابق مع إجراء (action) بل مع صفحة JSP، فسيتم عرض هذه الصفحة.
  • ما نراه في [2] هو إذن الصفحة HelloWorld.jsp التي درسناها.
  • في [4]، نلاحظ أن العلامة <title><s:text name="HelloWorld.message"/></title> لم تُحدث التأثير المطلوب، وكذلك العلامة <h2><s:property value="message"/></h2>. والسبب في ذلك هو أنه لم يتم استدعاء أي إجراء. وبالتالي، لم يتم تنفيذ قائمة المعترضات التي تُنفَّذ قبل الإجراء، ولا سيما تلك التي تدير عملية التدويل. لم يتم معالجة علامة التدويل <s:text ...> بشكل صحيح. علاوة على ذلك، فإن الخاصية message التي تشير إلى حقل message في الفئة Action1 غير موجودة. ومن هنا عدم ظهورها.

الآن، دعونا نتبع الرابط [English]. نحصل على الصفحة التالية:

  • في [1]، عنوان URL المطلوب. وقد شرحنا كيفية تكوين عنوان URL هذا. هذه المرة، يتم طلب إجراء Struts: الإجراء HelloWorld المُعرَّف في [example.xml].

<struts>
    <package name="example" namespace="/example" extends="struts-default">
        <action name="HelloWorld" class="example.HelloWorld">
            <result>/example/HelloWorld.jsp</result>
        </action>
    </package>
</struts>
  • تم تنفيذ الطريقة execute الخاصة بهذا الإجراء. لقد رأينا أنها تُرجع المفتاح success. من السطر 4 أعلاه، نستنتج أن الصفحة /example/HelloWorld.jsp يتم إرجاعها كاستجابة للعميل. وهذا ما نراه في [3].
  • في [1]، نرى أن عنوان URL المطلوب تم تعيينه بواسطة المعلمة request_locale=en. ستكون لغة الصفحات من الآن فصاعدًا هي الإنجليزية. في الواقع، يتم تخزين اختيار اللغة هذا في جلسة عمل المستخدم الذي سيحتفظ بهذا الاختيار حتى يقوم بتغييره.
  • في [2] و [3]، نرى عملية التدويل قيد التنفيذ. وقد أحدثت العلامات <title><s:text name="HelloWorld.message"/></title> و<h2><s:property value="message"/></h2> تأثيرها هذه المرة.

وإذا اخترنا الآن الرابط [Espanol]، فسنحصل على الصفحة باللغة الإسبانية:

2.9. Conclusion

لقد درسنا مثالًا تم إنشاؤه تلقائيًا بواسطة المكون الإضافي Struts 2 لـ NetBeans. ولاحظنا أنه كان من الصعب إلى حد ما تتبع معالجة الطلب. وتتدخل العناصر التالية في هذه العملية:

  • التكوين [web.xml]، [struts.xml]
  • الإجراء المنفذ: المعترضات والطريقة execute.

في البداية، قد تبدو آلية عمل Struts 2 معقدة. يتطلب الأمر بعض الوقت للتعود عليها. سنقدم الآن سلسلة من الأمثلة التي توضح كل منها جانبًا معينًا من جوانب Struts.