Skip to content

16. تطبيق ويب MVC في بنية ثلاثية الطبقات – المثال 2

16.1. مقدمة

لقد كتبنا تطبيق [people-01] بالهيكل التالي:

قامت طبقة [dao] بتنفيذ قائمة الأشخاص التي تتم إدارتها باستخدام كائن [ArrayList]. وقد سمح لنا ذلك بتجنب تعقيد طبقتي [dao] و[service] بشكل مفرط، حتى نتمكن من التركيز على طبقة [web]. نريد تطوير التطبيق نحو بيئة أكثر واقعية حيث يتم تخزين قائمة الأشخاص في جدول قاعدة بيانات. سيتطلب هذا منا تغيير طبقة [dao]. سيؤثر هذا على الطبقتين الأخريين. للاستفادة من استقلالية الطبقات التي يوفرها Spring IoC، سنأخذ تطبيق [people-01] ونقوم بتكوينه باستخدام Spring IoC:

سيُطلق على التطبيق الجديد اسم [people-02]. وبمجرد كتابته، نعلم أننا سنتمكن من تعديل طبقتي [DAO] و[service] دون تغيير الكود في طبقة [web]. وهذا بالضبط ما نسعى إليه.

نقوم بإنشاء مشروع Eclipse جديد [people-02] عن طريق نسخ ولصق مشروع [people-01]، كما هو موضح في القسم 6.2:

في [1]، نرى ظهور ملف التكوين، الذي سنحدد فيه الفاصوليا لطبقات [dao] و[service]. ومحتواه كما يلي:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- the dao class -->
    <bean id="dao" class="istia.st.mvc.personnes.dao.DaoImpl" init-method="init"/>
    <!-- service class -->
    <bean id="service" class="istia.st.mvc.personnes.service.ServiceImpl">
        <property name="dao">
            <ref local="dao" />
        </property>
    </bean>
</beans>
  • السطر 5: يُعرّف الفول المسمى [dao] كمثيل لفئة [DaoImpl]. بعد إنشاء المثيل، يتم تنفيذ طريقة [init] الخاصة بالمثيل.
  • الأسطر 7-10: تحدد الفاصوليا المسماة [service] كمثيل لفئة [ServiceImpl].
  • الأسطر 8–10: يتم تهيئة الخاصية [dao] لمثيل [DaoImpl] بالإشارة إلى طبقة [dao] التي تم إنشاؤها في السطر 5. تذكر أن فئة [ServiceImpl] تحتوي بالفعل على الخاصية [dao] ومُعيّن القيمة المقابل:
public class ServiceImpl implements IService {

    // the [dao] layer
    private IDao dao;

    public IDao getDao() {
        return dao;
    }

    public void setDao(IDao dao) {
        this.dao = dao;
    }
...

بالطبع، هذا الملف وحده لا يفعل شيئًا. ستستخدم وحدة التحكم [Application] هذا الملف في طريقة [init] الخاصة بها لإنشاء مثيل لطبقة [service]. دعونا نستذكر الإصدار السابق من طريقة [init] الخاصة بوحدة التحكم:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
...
    // service
    ServiceImpl service = null;

    // init
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
        // dao] layer instantiation
        DaoImpl dao = new DaoImpl();
        dao.init();
        // instantiation of the [service] layer
        service = new ServiceImpl();
        service.setDao(dao);
    }

في السطر 5، كان علينا تسمية فئة التنفيذ لطبقة [service] بشكل صريح، وفي السطر 12، فئة التنفيذ لطبقة [dao]. مع Spring IoC، تصبح طريقة [init] كما يلي:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
    // instance parameters
    ...

    // service
    private IService service = null;

    // init
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
    ...
        // instantiation of the [service] layer
        service = (IService) new XmlBeanFactory(new ClassPathResource("spring-config.xml")).getBean("service");
    }
  • السطر 7: لم يعد الحقل الخاص [service] من النوع [ServiceImpl] بل من النوع [IService]، أي من نوع واجهة طبقة [service]. وبالتالي، لم تعد طبقة [web] مرتبطة بتنفيذ محدد لهذه الواجهة.
  • السطر 14: تهيئة الحقل [service] من ملف التكوين [spring-config.xml].

هذه هي التغييرات الوحيدة التي يجب إجراؤها. دعونا ندمج هذا التطبيق الجديد في Tomcat، ونقوم بتشغيله، ثم نطلب عنوان URL [http://localhost:8080/personnes-02]:

Image

16.2. أرشفة تطبيق الويب

لقد قمنا بتطوير مشروع Eclipse/Tomcat لتطبيق ثلاثي الطبقات:

في إصدار مستقبلي، سيتم تخزين مجموعة الأشخاص في جدول قاعدة بيانات.

  • سيتطلب هذا إعادة كتابة طبقة [DAO]. وهذا أمر سهل الفهم.
  • سيتم تعديل طبقة [service] أيضًا. حاليًا، يتمثل دورها الوحيد في ضمان الوصول المتزامن إلى البيانات التي تديرها طبقة [dao]. ولهذا الغرض، قمنا بمزامنة جميع الطرق في طبقة [service]. وقد أوضحنا سبب وضع هذه المزامنة في هذه الطبقة بدلاً من طبقة [DAO]. في الإصدار الجديد، ستظل طبقة [service] تضطلع بالدور الوحيد المتمثل في مزامنة الوصول، ولكن سيتم التعامل مع ذلك من خلال معاملات قاعدة البيانات بدلاً من مزامنة أساليب Java.
  • ستبقى طبقة [الويب] دون تغيير.

لتسهيل الانتقال من إصدار إلى آخر، نقوم بإنشاء مشروع Eclipse جديد [mvc-personnes-02B]، وهو نسخة من المشروع السابق [mvc-personnes-02]، ولكن تم وضع طبقات [الويب، الخدمة، DAO، الكيانات] في أرشيفات .jar:

يحتوي المجلد [src] الآن على ملف تكوين Spring [spring-config.xml] فقط. وكان يحتوي سابقًا أيضًا على شفرة المصدر لفئات Java. تمت إزالة هذه العناصر واستبدالها بنسخها المُجمَّعة الموضوعة في أرشيفات [people-*.jar] الموضحة في [1]:

تم تكوين مشروع [mvc-personnes-02B] ليشمل أرشيفات [personnes-*.jar] في مسار ClassPath الخاص به.

نقوم بنشر مشروع الويب [mvc-personnes-02B] داخل Tomcat:

لاختبار المشروع، نقوم بتشغيل Tomcat ثم نطلب عنوان URL [http://localhost:8080/personnes02B]:

Image

ندعو القارئ إلى إجراء اختبارات إضافية.

في إصدار قاعدة البيانات، سنقوم بتغيير طبقتي [service] و [dao]. نريد أن نوضح أنه يكفي عندئذٍ استبدال أرشيفات [personnes-dao.jar] و [personnes-service.jar] في المشروع السابق بالأرشيفات الجديدة حتى يعمل تطبيقنا الآن مع قاعدة بيانات. لن نحتاج إلى المساس بأرشيفات طبقة [web] وطبقة [entities].