Skip to content

4. Розробка MVC (Модель – Представлення – Контролер)

Веб-додаток часто має трирівневу архітектуру:

Image

  • шар [dao] відповідає за доступ до даних, найчастіше до даних, що зберігаються в SGBD. Але це також можуть бути дані, що надходять від датчиків, мережі тощо...
  • Рівень [metier] реалізує «бізнес-алгоритми» додатка. Цей рівень не залежить від будь-якої форми взаємодії з користувачем. Отже, вона має працювати однаково добре як із консольним інтерфейсом, так і з веб-інтерфейсом чи багатофункціональним клієнтським інтерфейсом. Таким чином, її має бути можливо тестувати поза веб-інтерфейсом, зокрема за допомогою консольного інтерфейсу. Зазвичай це найстабільніший рівень архітектури. Він не змінюється, навіть якщо змінюється користувацький інтерфейс або спосіб доступу до даних, необхідних для функціонування додатка.
  • Рівень [interface utilisateur] — це інтерфейс (зазвичай графічний), який дозволяє користувачеві керувати додатком та отримувати від нього інформацію.

Обмін даними відбувається зліва направо:

  • користувач надсилає запит до шару [interface utilisateur]
  • цей запит форматується рівнем [interface utilisateur] і передається на рівень [métier]
  • якщо для обробки цього запиту рівню [métier] потрібні дані, він запитує їх у рівня [dao]
  • кожен запитаний рівень надсилає свою відповідь до попереднього рівня, аж до остаточної відповіді користувачеві.

Рівні [métier] та [dao] зазвичай використовуються через інтерфейси Java. Таким чином, рівень [métier] знає про рівень [dao] лише його інтерфейс(и) і не знає класів, що їх реалізують. Саме це забезпечує незалежність шарів один від одного: зміна реалізації шару [dao] ніяк не впливає на шар [métier], доки не змінюється визначення інтерфейсу шару [dao]. Те саме стосується шарів [interface utilisateur] та [métier].

Архітектура MVC (Модель — Вигляд — Контролер) розміщується в шарі [interface utilisateur], коли останній є веб-інтерфейсом:

Image

Обробка запиту клієнта відбувається за такими етапами:

  1. клієнт надсилає запит до контролера. Контролер обробляє всі запити клієнтів. Це вхідна точка додатка. Це «C» у MVC.
  2. контролер C обробляє цей запит. Для цього йому може знадобитися допомога бізнес-шару. Після обробки запиту клієнта він може викликати різні відповіді. Класичним прикладом є:
    • сторінка з повідомленням про помилку, якщо запит не вдалося обробити належним чином
    • сторінка підтвердження в іншому випадку
  3. контролер обирає відповідь (= вигляд), яку потрібно надіслати клієнту. Вибір відповіді, яку потрібно надіслати клієнту, передбачає кілька етапів:
    • вибрати об’єкт, який генеруватиме відповідь. Це те, що називають поданням V, тобто V з MVC. Цей вибір, як правило, залежить від результату виконання дії, яку запросив користувач.
    • надати йому дані, необхідні для формування цієї відповіді. Адже вона найчастіше містить інформацію, обчислену контролером. Ця інформація утворює так звану модель M подання, M у MVC.
    • Отже, етап 3 полягає у виборі подання V та побудові необхідної для нього моделі M.
  4. контролер C запитує обраний вигляд про його відображення. Найчастіше це полягає у виконанні певного методу виду V, який відповідає за формування відповіді для клієнта. У цьому документі ми будемо називати «видом» як об’єкт, що формує відповідь для клієнта, так і саму цю відповідь. У літературі MVC це питання не роз’яснено. Якби саме відповідь називалася «видом», то об’єкт, що генерує цю відповідь, можна було б назвати «генератором виду».
  5. Генератор подання V використовує модель M, підготовлену контролером C, для ініціалізації динамічних частин відповіді, яку він має надіслати клієнту.
  6. Відповідь надсилається клієнту. Точна форма відповіді залежить від генератора подання. Це може бути потік HTML, PDF, файл Excel тощо.

Методологія веб-розробки MVC не обов’язково вимагає використання зовнішніх інструментів. Таким чином, можна розробити веб-додаток на Java з архітектурою MVC, використовуючи простий JDK та базові бібліотеки веб-розробки. Для простих додатків можна використовувати такий підхід:

  • контролер забезпечується єдиним сервлетом. Це «C» у MVC.
  • усі запити клієнта містять атрибут action, наприклад (http://.../appli?action=liste).
  • Залежно від значення атрибута action сервлет запускає внутрішній метод типу [doAction(...)].
  • Метод [doAction] виконує дію, яку вимагає користувач. Для цього, за потреби, він використовує рівень [métier].
  • Залежно від результату виконання метод [doAction] визначає, яку сторінку JSP відобразити. Це представлення V моделі MVC.
  • Сторінка JSP містить динамічні елементи, які має надати сервлет. Метод [doAction] надасть ці елементи. Це модель подання, M у MVC. Ця модель найчастіше розміщується в контексті запиту (request.setAttribute("ключ", "значення"), або, рідше, у контексті сесії чи додатка. Сторінка JSP має доступ до цих трьох контекстів.
  • Метод [doAction] відображає представлення, передаючи потік виконання обраній сторінці JSP. Для цього він використовує інструкцію типу [getServletContext() .getRequestDispatcher(" pageJSP ").forward(request, response)].

Цей архітектурний шаблон (Design Pattern) MVC називається «Front Controller» або моделлю з єдиним контролером. Єдиний сервлет обробляє всі запити всіх користувачів.

Повернемося до архітектури попереднього веб-додатку:

Image

Ця архітектура відповідає такій архітектурі n-Tier:

Image

Насправді існує лише один рівень — рівень веб-інтерфейсу. Загалом, веб-додаток MVC, побудований на основі сервлетів та сторінок JSP, матиме таку архітектуру:

Image

Для простих додатків цієї архітектури цілком достатньо. Коли ви написали кілька додатків такого типу, ви помітите, що сервлети двох різних додатків:

  1. мають однаковий механізм визначення того, який метод [doAction] потрібно виконати для обробки дії, запитуваної користувачем
  2. фактично відрізняються лише змістом цих методів [doAction]

Тоді виникає велика спокуса:

  • винести обробку (1) у загальний сервлет, який не знає про додаток, що його використовує
  • делегувати обробку (2) зовнішнім класам, оскільки загальний сервлет не знає, у якому додатку він використовується
  • встановити зв’язок між дією, яку вимагає користувач, та класом, що має її обробити, за допомогою конфігураційного файлу

З’явилися інструменти, які часто називають «фреймворками», щоб надати розробникам зазначені вище можливості. Найстарішим і, ймовірно, найвідомішим із них є Struts (http://struts.apache.org/). Jakarta Struts — це проєкт Apache Software Foundation (www.apache.org). Цей фреймворк описано за посиланням (http://tahe.developpez.com/java/struts/).

З’явився нещодавно фреймворк Spring (http://www.springframework.org/), який пропонує можливості, аналогічні до Struts. Його використання описано в кількох статтях (http://tahe.developpez.com/java/springmvc-part1/).

Тепер ми наведемо приклад архітектури MVC на основі сервлетів та сторінок JSP.