Skip to content

16. Веб-додаток MVC у трирівневій архітектурі — Приклад 2

16.1. Introduction

Ми написали додаток [personnes-01], що має таку структуру:

Рівень [dao] реалізовував список осіб, що управляється за допомогою об’єкта [ArrayList]. Це дозволило нам не заглиблюватися в рівні [dao] та [service], щоб зосередитися на рівні [web]. Ми хочемо розвинути додаток у бік більш реалістичного середовища, де список осіб зберігатиметься в таблиці бази даних. Це змусить нас змінити рівень [dao]. Це вплине на два інші рівні. Щоб скористатися незалежністю шарів, яку забезпечує Spring IoC, ми візьмемо додаток [personnes-01] і налаштуємо його за допомогою Spring IoC:

Новий додаток матиме назву [personnes-02]. Після її написання ми знаємо, що зможемо змінювати шари [dao] та [service] без внесення змін до коду шару [web]. Саме цього ми й прагнемо.

Ми створюємо новий проєкт Eclipse [personnes-02] шляхом копіювання та вставлення проєкту [personnes-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>
    <!-- клас DAO -->
    <bean id="dao" class="istia.st.mvc.personnes.dao.DaoImpl" init-method="init"/>
    <!-- клас-сервіс -->
    <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 {

     // шар [dao]
    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 {
...
     // сервіс
    ServiceImpl service = null;

     // ініціалізація
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
         // інстанціювання шару [dao]
        DaoImpl dao = new DaoImpl();
        dao.init();
         // інстанціювання шару [service]
        service = new ServiceImpl();
        service.setDao(dao);
    }

У рядку 5 ми були змушені явно вказати ім’я класу реалізації шару [service], а в рядку 12 — класу реалізації шару [dao]. З Spring IoC метод [init] виглядає наступним чином:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
     // параметри екземпляра
    ...

     // сервіс
    private IService service = null;

     // ініціалізація
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
    ...
         // інстанціювання шару [service]
        service = (IService) new XmlBeanFactory(new ClassPathResource("spring-config.xml")).getBean("service");
    }
  • рядок 7: приватне поле [service] більше не має типу [ServiceImpl], а має типи [IService], c.a.d. типу інтерфейсу шару [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.
  • Рівень [web] залишиться без змін.

Щоб полегшити перехід від однієї версії до іншої, ми створюємо новий проект Eclipse [mvc-personnes-02B] — копію попереднього проекту [mvc-personnes-02], але в якому шари [web, service, dao, entites] було поміщено в архіви .jar:

Папка [src] тепер містить лише файл конфігурації Spring [spring-config.xml]. Раніше він також містив вихідний код Java-класів. Ці елементи зникли, їх замінили скомпільовані версії, розміщені в архівах [personnes-*.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] та рівня [entites].