5. Веб-додаток MVC [personne] — версія 1
5.1. Види додатка
Додаток використовує ту саму форму, що й у попередніх прикладах. Перша сторінка додатка виглядає так:

Цю сторінку ми назвемо [formulaire]. Якщо ввести правильні дані, вони відображаються на сторінці, яку ми назвемо [réponse]:

Якщо дані введені неправильно, помилки відображаються у вікні з назвою [erreurs]:

5.2. Архітектура додатка
Веб-додаток [personne1] матиме таку архітектуру:

Ця архітектура є однорівневою: немає шарів [métier] або [dao], є лише один шар [web]. [ServletPersonne] — це контролер додатка, який обробляє всі запити клієнтів. Для відповіді на них він використовує один із трьох виглядів [formulaire, réponse, erreurs].
Нам потрібно з’ясувати, як контролер [ServletPersonne] визначає дію, яку він повинен виконати після отримання запиту від користувача. Запит клієнта — це потік HTTP, який відрізняється залежно від того, чи зроблено його за допомогою команди GET чи POST.
Запит GET
У цьому випадку потік HTTP виглядає наступним чином:
У рядку 1 вказано URL-адресу запиту, наприклад:
Цю URL-адресу можна використовувати для визначення дії, яку потрібно виконати. Для цього можна використовувати різні методи:
- параметр URL-адреси визначає дію, наприклад [/appli?action=ajouter&id=4]. У цьому випадку параметр [action] вказує контролеру, яку дію від нього вимагають.
- останній елемент URL-адреси визначає дію, наприклад [/appli/ajouter?id=4]. У цьому випадку останній елемент URL-адреси [/ajouter] використовується контролером для визначення дії, яку він повинен виконати.
Можливі й інші варіанти. Два попередні є найпоширенішими.
Запит POST
У цьому випадку потік HTTP виглядає наступним чином:
У рядку 1 вказано запитуваний URL-адресу, наприклад:
Цю URL-адресу можна використовувати для визначення дії, яку потрібно виконати, як у випадку з GET. У випадку з GET параметр [action] був інтегрований у URL. Це може бути також і в даному випадку, як-от:
Але параметр [action] також може бути включений до надісланих параметрів (рядок 15 вище), як у:
Далі ми використаємо ці різні методи, щоб вказати контролеру, що він повинен робити:
- включити параметр action у запитуваний URL-адресу:
- відправити параметр action:
- використовувати останній елемент URL-адреси як ім'я дії:
5.3. Проєкт Eclipse
Щоб створити проект Eclipse [mvc-personne-01] для веб-додатка [personne1], слід дотримуватися покрокової інструкції, описаної в розділі 3.1.

Не слід залишати контекст [mvc-personne-01], запропонований за замовчуванням. Слід вибрати [personne1], як показано нижче:

Отриманий результат такий:

Якщо раптом знадобиться змінити контекст веб-додатку, слід використати опцію [clic droit sur projet -> Properties -> J2EE]:

У [1] вказується новий контекст.
Ми створимо підпапку [vues] у папці [WEB-INF]: [clic droit sur WEB-INF -> New -> Folder]:
![]() | ![]() |
Новий проект тепер виглядає так:

Після завершення проект матиме такий вигляд:

- контролер [ServletPersonne] знаходиться у папці [src]
- сторінки JSP з переглядів [formulaire, réponse, erreurs] знаходяться у папці [WEB-INF/vues], що не дозволяє користувачеві безпосередньо їх викликати, як показано у прикладі нижче:

Тепер ми опишемо різні компоненти веб-додатку [/personne1]. Читачеві пропонується створювати їх у міру читання.
5.4. Налаштування веб-додатку [personne1]
Файл web.xml додатка /personne1 матиме такий вигляд:
<?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>
Що міститься в цьому файлі конфігурації?
- рядки 34–37: URL /main обробляється сервлетом з назвою «person»
- рядки 10–13: сервлет з назвою «personne» є екземпляром класу [ServletPersonne]
- рядки 14–19: визначають параметр конфігурації з назвою [urlReponse]. Це URL-адреса подання [réponse].
- рядки 20–25: визначають параметр конфігурації з іменем [urlErreurs]. Це URL-адреса подання [erreurs].
- рядки 26–31: визначають параметр конфігурації з назвою [urlFormulaire]. Це URL-адреса подання [formulaire].
- рядок 40: [index.jsp] буде головною сторінкою додатка.
URL-адреси сторінок JSP та переглядів [formulaire, réponse, erreurs] окремо задаються конфігураційними параметрами. Це дозволяє переміщувати їх без необхідності перекомпіляції додатка.
Коли користувач звернеться за URL-адресою [/personne1], відповідь надішле файл [index.jsp] (файл-початкова сторінка, рядок 40). Цей файл знаходиться в кореневій папці [WebContent]:

Його вміст такий:
<%@ 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: відповідь HTTP/1.1, щоб вказати серверу перенаправити запит на інший URL
- рядок 4: URL, на яку має перенаправитися браузер
Після отримання цієї відповіді браузер, відповідно до вказівки (рядок 4), надішле запит на URL-адресу [/personne1/main]. Файл [web.xml] додатка [/personne1] вказує, що цей запит буде оброблено контролером [ServletPersonne] (рядки 35–36).
5.5. Код подання
Ми розпочинаємо розробку веб-додатку з написання його представлень. Вони дозволяють визначити потреби користувача щодо графічного інтерфейсу та можуть бути протестовані без контролера.
5.5.1. Вигляд [formulaire]
Цей вигляд відповідає формі для введення імені та віку:

тип HTML | ім'я | роль | |
<input type= "text "> | txtNom | введення імені | |
<input type= "text "> | txtAge | введення віку | |
<input type= "submit "> | відправлення введених значень на сервер за адресою /personne1/main | ||
<input type= "reset "> | для повернення сторінки до стану, в якому вона була спочатку отримана браузером | ||
<input type= "button "> | для очищення вмісту полів введення [1] та [2] |
Вона генерується сторінкою JSP [formulaire.jsp]. Її шаблон складається з таких елементів:
- [nom]: ім’я (String), знайдене в атрибутах сесії, пов’язаних із ключем «nom»
- [age]: вік (String), знайдений у атрибутах сесії, пов’язаних із ключем «age»
Вигляд [formulaire] отримується, коли користувач запитує URL-адресу [/personne1/main], c.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>
- рядки 6–7: сторінка JSP спочатку отримує з запиту [request] елементи [nom, age] своєї моделі. Під час нормальної роботи додатка цю модель створюватиме контролер [ServletPersonne].
- рядки 18–38: сторінка JSP згенерує форму HTML (тег <form>)
- рядок 18: тег <form> не має атрибута action для вказівки URL-адреси, яка має обробляти значення, надіслані кнопкою [Envoyer] типу submit (рядок 32). Тоді значення форми будуть відправлені на URL-адресу, з якої була отримана форма, тобто на URL-адресу контролера [ServletPersonne]. Таким чином, цей контролер використовується як для генерації порожньої форми, яка спочатку запитувалася за допомогою GET, так і для обробки введених даних, які будуть надіслані йому за допомогою кнопки [Envoyer].
- Передані значення відповідають полям HTML, [txtNom] (рядок 22), [txtAge] (рядок 26) та [action] (рядок 37). Цей останній параметр дозволить контролеру зрозуміти, що йому потрібно зробити.
- Під час початкового відображення форми поля введення [txtNom, txtAge] ініціалізуються відповідно змінними [nom] (рядок 22) та [age] (рядок 26). Ці змінні отримують значення своїх атрибутів із запиту (рядки 6–7), які, як відомо, ініціалізуються сервлетом. Отже, саме сервлет визначає початковий вміст полів введення форми.
- рядок 33: кнопка [Rétablir] типу [reset] дозволяє повернути форму до того стану, в якому вона перебувала, коли браузер її отримав.
- рядок 34: кнопка [Effacer] типу [reset] наразі не виконує жодної функції.
Надалі ми будемо називати цей вигляд «[formulaire(nom, age)]», коли захочемо вказати одночасно назву виду та його модель. Крім того, слід пам’ятати, що коли користувач натискає на кнопку [Envoyer], параметри [txtNom, txtAge] надсилаються на URL-адресу [/personne1/main].
5.5.2. Вигляд [reponse]
Цей вигляд відображає значення, введені у форму, якщо вони є дійсними:

Вона генерується сторінкою JSP [reponse.jsp]. Її шаблон складається з таких елементів:
- [nom]: ім’я (String), яке буде знайдено в атрибутах сесії, пов’язане з ключем «nom»
- [age]: вік (String), який буде знайдено в атрибутах сесії, пов’язаний із ключем «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>
- рядки 6–7: сторінка JSP спочатку отримує із запиту [request] елементи [nom, age] своєї моделі. Під час нормальної роботи додатка саме контролер [ServletPersonne] буде формувати цю модель.
- Елементи [nom, age] моделі потім відображаються у рядках 20 та 24
Надалі ми називаємо цей вигляд «[réponse(nom, age)]».
5.5.3. Вигляд [erreurs]
Цей вигляд повідомляє про помилки введення даних у формі:

Вона генерується сторінкою JSP [erreurs.jsp]. Її шаблон складається з таких елементів:
- [erreurs]: список (ArrayList) повідомлень про помилки, який міститься в атрибутах запиту та пов’язаний із ключем «помилки»
Код сторінки 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");
}//for
%>
</ul>
</body>
</html>
- рядок 8: сторінка JSP починається з вилучення із запиту [request] елемента [erreurs] своєї моделі. Цей елемент представляє об’єкт типу ArrayList, що складається з елементів типу String. Ці елементи є повідомленнями про помилки. Під час нормальної роботи додатка саме контролер [ServletPersonne] формуватиме цю модель.
- рядки 18–22: відображають список повідомлень про помилки. Для цього доводиться писати код Java у тілі HTML сторінки. Слід завжди прагнути звести його до мінімуму, щоб не захаращувати код HTML. Пізніше ми побачимо, що існують рішення, які дозволяють зменшити обсяг коду Java на сторінках JSP.
- рядок 4: зверніть увагу на тег імпорту пакетів, необхідних для сторінки JSP
Далі ми називаємо цей вигляд «[erreurs(erreurs)]».
5.6. Тестування подання
Можна перевірити правильність роботи сторінок JSP, не написавши контролер. Для цього необхідні дві умови:
- необхідно мати можливість запитувати їх безпосередньо в додатку, оминаючи контролер
- сторінка JSP повинна самостійно ініціалізувати модель, яку зазвичай створює контролер
Щоб провести ці тести, ми дублюємо сторінки JSP з поданнями у папці [/WebContent/JSP] проекту Eclipse:

Потім у папці 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>
...
Рядки 3–7 було додано для створення шаблону, необхідного для сторінки рядків 11–12.
[reponse.jsp]:
...
<%
// -- тест: створюємо шаблон сторінки
request.setAttribute("nom","milou");
request.setAttribute("age","10");
%>
<%
// отримуємо дані з шаблону
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
<html>
<head>
...
Рядки 3–7 було додано для створення шаблону, необхідного для сторінки рядків 11–12.
[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>
...
Рядки 3–9 було додано для створення шаблону, необхідного для сторінки, зазначеної в рядку 13.
Запустіть Tomcat, якщо це ще не зроблено, а потім завантажте такі URL-адреси:
![]() | ![]() |
![]() |
Ми отримуємо очікувані результати. Тепер, коли ми маємо достатню впевненість у сторінках JSP додатка, можемо перейти до написання його контролера [ServletPersonne].
5.7. Контролер [ServletPersonne]
Залишилося написати серце нашого веб-додатку — контролер. Його роль полягає в тому, щоб:
- отримувати запит від клієнта,
- обробити запитувану ним дію,
- відправити у відповідь відповідний вигляд.
Контролер [ServletPersonne] оброблятиме такі дії:
№ | запит | джерело | обробка |
1 | [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] має такий вигляд:
- рядки 20–22: метод [init], що виконується під час початкового завантаження сервлета
- рядки 25–28: метод [doGet], який викликається веб-сервером, коли до додатка надходить запит типу GET
- рядки 42–46: метод [doPost], що викликається веб-сервером, коли до додатка надходить запит типу POST. Як показано, цей запит також оброблятиметься методом [doGet] (рядок 45).
- рядки 31–33: метод [doInit] обробляє дію № 1 [GET /personne1/main]
- рядки 36–39: метод [doValidationFormulaire] обробляє дію № 2 [POST /personne1/main] із переданими параметрами [txtNom, txtAge, action].
Тепер опишемо різні методи контролера
5.7.2. Ініціалізація контролера
Коли клас контролера завантажується контейнером сервлетів, виконується його метод [init]. Це відбудеться лише один раз. Після завантаження в пам'ять контролер залишатиметься там і оброблятиме запити різних клієнтів. Для кожного клієнта створюється окремий потік виконання, і таким чином методи контролера виконуються одночасно різними потоками. Нагадаємо, що з цієї причини контролер не повинен мати полів, які його методи могли б змінювати. Його поля повинні бути доступними лише для читання. Вони ініціалізуються методом [init], що є його основною функцією. Цей метод має особливість: він виконується лише один раз одним потоком. Отже, у цьому методі не виникає проблем з паралельним доступом до полів контролера. Метод [init] призначений для ініціалізації об’єктів, необхідних для веб-додатка, які будуть спільними для всіх клієнтських потоків у режимі «тільки для читання». Ці спільні об’єкти можна розмістити у двох місцях:
- у приватних полях контролера
- контекст виконання додатка (ServletContext)
Код методу [init] контролера [ServletPersonne] має такий вигляд:
- рядок 16: отримується конфігурація веб-додатку c.a.d. Зміст файлу [web.xml]
- у рядках 19–29 отримуються параметри ініціалізації сервлета, імена яких визначені в таблиці [paramètres] у рядку 9
- рядок 21: отримується значення параметра
- рядок 25: якщо параметр відсутній, помилка додається до списку помилок [erreursInitialisation], який спочатку був порожнім (рядок 8).
- рядок 28: якщо параметр присутній, він зберігається разом зі своїм значенням у словнику [params], який спочатку був порожнім (рядок 10).
- рядки 31–35: параметр [urlErreurs] має обов’язково бути присутнім, оскільки він вказує URL-адресу подання [erreurs], здатного відображати можливі помилки ініціалізації. Якщо його немає, додаток припиняється шляхом запуску [ServletException] (рядок 33).
5.7.3. Метод [doGet]
Метод [doGet] обробляє як запити GET, так і POST у сервлеті, оскільки метод [doPost] перенаправляє на метод [doGet]. Його код такий:
- рядки 18–25: перевіряється, чи список помилок ініціалізації порожній. Якщо це не так, відображається представлення [erreurs(erreursInitialisation)], яке повідомить про помилку або помилки.
Щоб зрозуміти цей код, слід згадати шаблон подання [erreurs]:
Вигляд [erreurs] очікує на елемент ключа «errors» у запиті. Контролер створює цей елемент у рядку 20.
- рядок 28: отримується метод [get] або [post], який клієнт використав для формування свого запиту
- рядок 30: отримується значення параметра [action] із запиту. Нагадаємо, що в нашому додатку лише запит № 2 [POST /personne1/main] має параметр [action]. У цьому запиті він має значення [validationFormulaire].
- рядки 31–34: якщо параметр [action] відсутній, йому присвоюється значення «init». Це відбудеться під час початкового запиту № 1 [GET /personne1/main].
- рядки 36–40: обробка запиту № 1 [GET /personne1/main].
- рядки 41–45: обробка запиту № 2 [POST /personne1/main].
- рядок 47: якщо ситуація не відповідає жодному з двох попередніх випадків, діють так, ніби це випадок № 1
5.7.4. Метод [doInit]
Цей метод обробляє запит № 1 [GET /personne1/main]. Для цього запиту він повинен надіслати порожній вигляд [formulaire(nom,age)]. Його код такий:
- рядки 18–19: відображається представлення [formulaire]. Нагадаємо, який шаблон очікується для цього представлення:
<%
// отримуємо дані з моделі
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
- рядки 16–17: шаблон [nom,age] з подання [formulaire] ініціалізується порожніми рядками.
5.7.5. Метод [doValidationFormulaire]
Цей метод обробляє запит № 2 [POST /personne1/main], у якому передані параметри — [action, txtNom, txtAge]. Його код такий:
- рядки 16–17: із запиту клієнта отримуються значення параметрів «txtNom» та «txtAge».
- рядки 19–26: перевіряється правильність цих двох параметрів
- рядки 28–33: якщо один із параметрів є помилковим, відображається подання [erreurs(erreursAppel)]. Нагадаємо модель цього подання:
<%
// отримуємо дані з шаблону
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
%>
- рядки 35–38: якщо обидва отримані параметри «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, дотримуючись процедури, описаної в розділі 3.3:

Запустіть Tomcat. Після цього можна продовжити тестування, наведене як приклад у розділі 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>
-->
Запускаємо / перезапускаємо Tomcat і звертаємося за URL-адресою [http://localhost:8080/personne1/main]. Отримуємо таку відповідь:





