6. Веб-додаток MVC [personne] – версія 2
Тепер ми запропонуємо варіанти попереднього додатка [/personne1], які ми назвемо [/personne2, /personne3, ...]. Ці варіанти не змінюють початкову архітектуру додатка, яка залишається такою:

Щодо цих варіантів ми будемо коротше пояснювати. Ми представимо лише зміни, внесені порівняно з попередньою версією.
6.1. Introduction
Тепер ми пропонуємо додати до нашого додатка управління сесіями. Нагадаємо наступні моменти:
- діалог «клієнт-сервер» HTTP — це послідовність запитів і відповідей, що не пов’язані між собою
- сесія слугує пам’яттю між різними послідовностями запит-відповідь одного й того самого користувача. Якщо є N користувачів, то існує N сесій.
Наступна послідовність екранів ілюструє те, як тепер має працювати додаток:
Обмін № 1
![]() | ![]() |
Нововведення полягає в тому, що у вікні [erreurs] було додано посилання для повернення до форми.
Обмін № 2
![]() | ![]() |
У обміні № 1 користувач вказав для пари (ім'я, вік) значення (xx, yy). Якщо під час обміну сервер отримав ці значення, то наприкінці обміну він їх «забуває». Однак можна помітити, що під час обміну № 2 він здатний знову відобразити ці значення у своїй відповіді. Саме поняття сесії в цьому випадку дозволяє веб-серверу запам’ятовувати дані під час послідовних обмінів між клієнтом і сервером. Існують й інші можливі рішення цієї проблеми.
Під час обміну № 1 сервер збереже в сесії пару (ім’я, вік), яку клієнт надіслав йому, щоб мати змогу відобразити її під час обміну № 2.
Ось ще один приклад реалізації сесії між двома обмінами:
Обмін № 1
![]() | ![]() |
Нововведення полягає в тому, що на сторінці відповіді було додано посилання для повернення до форми.
Обмін № 2
![]() | ![]() |
6.2. Проєкт Eclipse
Щоб створити проект Eclipse [mvc-personne-02] для веб-додатку [/personne2], ми скопіюємо проект Eclipse [mvc-personne-01], щоб зберегти існуючі дані. Для цього виконаємо наступні дії:
[clic droit sur projet mvc-personne-01 -> Copy]:

потім [clic droit dans Package Explorer -> Paste]:
![]() | ![]() - вкажімо в [1] назву нового проєкту, а в [2] — назву існуючої, але порожньої папки |
Проект [mvc-personne-02] буде створено:

Наразі він ідентичний проекту [mvc-personne-01]. Нам доведеться внести кілька змін вручну, перш ніж ми зможемо ним скористатися. Перейдемо до вікна [Servers] і спробуємо додати цю нову програму до тих, що керуються Tomcat:
![]() | ![]() |
Як бачимо, у [1] новий проєкт [mvc-personne-02] не розпізнається Tomcat. Щоб він його розпізнав, потрібно змінити файл конфігурації проєкту [mvc-personne-02]. Скористаємося опцією [File / Open File], щоб відкрити файл [<mvc-personne-02>/.settings/.component]:
<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId">
<wb-module deploy-name="mvc-personne-01">
<wb-resource deploy-path="/" source-path="/WebContent"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
<property name="java-output-path" value="/build/classes/"/>
<property name="context-root" value="personne1"/>
</wb-module>
</project-modules>
У рядку 3 вказано ім’я веб-модуля, який потрібно розгорнути в Tomcat. Це ім’я тут збігається з назвою проєкту [mvc-personne-01]. Змінимо його на [mvc-personne-02]:
<wb-module deploy-name="mvc-personne-02">
Крім того, ми можемо скористатися нагодою, щоб у рядку 7 змінити назву контексту додатка [mvc-personne-02], яка конфліктує з назвою проєкту [mvc-personne-01]:
<property name="context-root" value="personne2"/>
Цю другу зміну можна було б внести безпосередньо в Eclipse. Натомість я не знайшов способу внести першу зміну без використання файлу конфігурації.
Зробивши це, ми зберігаємо новий файл [.content], а потім закриваємо та перезапускаємо Eclipse, щоб зміни вступили в силу.
Після перезапуску Eclipse спробуємо виконати операцію, яка раніше завершилася невдачею:
![]() | ![]() |
Цього разу проект [mvc-personne-02] бачиться коректно. Додаємо його до списку проектів, налаштованих для виконання в Tomcat:

6.3. Налаштування веб-додатку [personne2]
Файл web.xml додатка /personne2 має такий вигляд:
<?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-02</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>
<init-param>
<param-name>urlControleur</param-name>
<param-value>
main
</param-value>
</init-param>
<init-param>
<param-name>lienRetourFormulaire</param-name>
<param-value>
Retour au formulaire
</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>
Цей файл ідентичний файлу попередньої версії, за винятком того, що в ньому оголошено два нових параметри ініціалізації:
- рядок 6: ім’я для відображення веб-додатка змінилося на [mvc-personne-02]
- рядки 31–36: визначають параметр конфігурації з назвою [urlControleur], який є URL-адресою [main], що веде до сервлету [ServletPersonne]
- рядки 37–42: визначають параметр конфігурації з назвою [lienRetourFormulaire], який є текстом посилання для повернення до форми зі сторінок JSP, [erreurs.jsp] та [reponse.jsp].
Головна сторінка [index.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">
<%
response.sendRedirect("/personne2/main");
%>
- рядок 5: сторінка [index.jsp] перенаправляє клієнта на URL-адресу контролера [ServletPersonne] додатка [/personne2].
6.4. Код подання
6.4.1. Вигляд [formulaire]
Цей вигляд ідентичний тому, що був у попередній версії:

Вона генерується наступною сторінкою JSP [formulaire.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)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
<html>
<head>
<title>Personne - formulaire</title>
</head>
<body>
<center>
<h2>Personne - formulaire</h2>
<hr>
<form action="<%=urlAction%>" 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>
Нові можливості:
- у рядку 19 форма тепер має атрибут [action], значенням якого є URL-адреса, на яку браузер повинен відправити значення форми, коли користувач натисне кнопку [Envoyer] типу submit. Змінна [urlAction] матиме значення action="main". Вигляд [formulaire] відображається після таких дій користувача:
- початковий запит: GET /personne2/main
- натискання на посилання [Retour au formulaire]: GET /personne2/main?action=retourFormulaire
Оскільки атрибут [action] не вказує абсолютну URL-адресу (що починається з /), а відносну (що не починається з /), браузер використає першу частину URL-адреси поточної сторінки [/personne2] і додасть до неї відносну URL-адресу. Отже, URL-адреса POST буде [/personne2/main] — це URL-адреса контролера. Цей запит POST супроводжуватиметься параметрами [txtNom, txtAge, action] із рядків 23, 27 та 38.
- рядок 8: отримуємо значення елемента [urlAction] з моделі. Воно шукається в атрибутах поточного запиту. Воно буде використано в рядку 19.
- рядки 6–7: отримуються значення елементів [nom, age] з моделі. Вони шукаються в атрибутах сесії, а не в атрибутах запиту, як у попередній версії. Це зроблено для задоволення потреб запиту [GET /personne2/main?action=retourFormulaire], пов’язаного з переглядами [réponse] та [erreurs]. Перед відображенням цих двох переглядів контролер розміщує в сесії дані, введені у форму, що дозволяє йому знайти їх, коли користувач використовує посилання [Retour au formulaire] для переглядів [réponse] та [erreurs].
6.4.2. Вигляд [reponse]
Цей вигляд відображає значення, введені у форму, якщо вони є дійсними:
![]() | ![]() |
Порівняно з попередньою версією, нововведенням є посилання [Retour au formulaire]. Вигляд генерується наступною сторінкою 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");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
<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>
<br>
<a href="?action=retourFormulaire"><%= lienRetourFormulaire %></a>
</body>
</html>
- рядок 31: посилання для повернення до форми. Це посилання складається з двох частин:
- ціль [href="?action=retourFormulaire"]. Вигляд [réponse] відображається після POST форми [formulaire.jsp] за URL-адресою [/personne2/main]. Отже, саме ця остання URL-адреса відображається в браузері, коли відкривається вид [réponse]. Клік на посилання [Retour au formulaire] спричинить запит GET від браузера на URL-адресу, вказану атрибутом [href] цього посилання, у даному випадку «?action=retourFormulaire». Якщо в [href] URL-адреса відсутня, браузер використає URL-адресу поточного вікна, c.a.d. [/personne2/main]. У підсумку, клік на посилання [Retour au formulaire] спричинить запит GET від браузера на URL-адресу [/personne2/main?action=retourFormulaire], c.a.d — URL-адреса контролера додатка, що супроводжується параметром [action], який вказує йому, що саме потрібно зробити.
- Текст посилання. Він буде частиною шаблону, переданого на сторінку контролером і отриманого в рядку 10.
6.4.3. Вигляд [erreurs]
Цей вигляд повідомляє про помилки введення даних у формі:
![]() | ![]() |
Порівняно з попередньою версією, нововведенням є посилання [Retour au formulaire]. Вигляд генерується наступною сторінкою 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");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
<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");
}//для
%>
</ul>
<br>
<a href="?action=retourFormulaire"><%= lienRetourFormulaire %></a>
</body>
</html>
- рядок 26: посилання для повернення до форми. Це посилання ідентичне тому, що міститься у вигляді [réponse]. Читачеві пропонується, за необхідності, ще раз ознайомитися з поясненнями, наданими для цього виду.
6.5. Тестування переглядів
Щоб провести тестування попередніх переглядів, ми дублюємо їхні сторінки JSP у папці /WebContent/JSP проекту Eclipse:

Потім у папці JSP сторінки змінюються наступним чином:
[formulaire.jsp]:
...
<%
// -- тест: створюється шаблон сторінки
session.setAttribute("nom","tintin");
session.setAttribute("age","30");
request.setAttribute("urlAction","main");
%>
<%
// отримуємо дані з шаблону
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
Рядки 4–5 було додано для створення шаблону, необхідного для сторінки, рядки 11–13.
[reponse.jsp] :
<%
// -- тест: створюємо шаблон сторінки
request.setAttribute("nom","milou");
request.setAttribute("age","10");
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// отримуємо дані з шаблону
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
Рядки 4–6 було додано для створення шаблону, необхідного для сторінки, що міститься в рядках 11–13.
[erreurs.jsp]:
<%
// -- тест: створюємо шаблон сторінки
ArrayList<String> erreurs1=new ArrayList<String>();
erreurs1.add("erreur1");
erreurs1.add("erreur2");
request.setAttribute("erreurs",erreurs1);
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// отримуємо дані з шаблону
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
Рядки 4–8 було додано для створення шаблону, необхідного для сторінки, що міститься в рядках 13–14.
Запустимо Tomcat, якщо це ще не зроблено, а потім звернемося за такими URL-адресами:
![]() | ![]() |
![]() |
Ми отримуємо очікувані результати.
6.6. Контролер [ServletPersonne]
Контролер [ServletPersonne] веб-додатку [/personne2] оброблятиме такі дії:
№ | запит | джерело | обробка |
1 | [GET /personne2/main] | URL-адреса, введена користувачем | - надіслати порожній вигляд [formulaire] |
2 | [POST /personne2/main] з параметрами [txtNom, txtAge, action], відправлені | натиснути кнопку [Envoyer] у вікні [formulaire] | - перевірити значення параметрів [txtNom, txtAge] - якщо вони неправильні, надіслати вигляд [erreurs(erreurs)] - якщо вони правильні, надіслати вигляд [reponse(nom,age)] |
3 | [GET /personne2/main? action=retourFormulaire] | натисніть на посилання [Повернутися до форму] з переглядів відповіді] та [erreurs]. | - надіслати попередньо заповнений вигляд [formulaire] з останніми введеними значеннями |
Отже, у нас з’явилася нова дія, яку потрібно обробити: [GET /personne2/main?action=retourFormulaire].
6.6.1. Скелет контролера
Скелет контролера [ServletPersonne] майже ідентичний скелету попередньої версії:
Нові особливості:
- рядок 4: використання сесії вимагає імпортувати пакет [HttpSession]
- рядки 28–30: новий метод [doRetourFormulaire] обробляє нову дію: [GET /personne2/main?action=retourFormulaire].
6.6.2. Ініціалізація контролера [init]
Метод [init] ідентичний методу попередньої версії. Він перевіряє наявність у файлі [web.xml] елементів, оголошених у масиві [paramètres]:
- рядок 5: додано параметри [urlControleur] (URL-адреса контролера) та [lienRetourFormulaire] (текст посилання для переглядів [réponse] та [erreurs]).
6.6.3. Метод [doGet]
Метод [doGet] повинен обробляти дію [GET /personne2/main?action=retourFormulaire], якої раніше не існувало:
- рядки 6–14: перевіряється, чи список помилок ініціалізації порожній. Якщо це не так, відображається вікно [erreurs(erreursInitialisation)], яке повідомить про помилку або помилки.
Щоб зрозуміти цей код, слід згадати шаблон подання [erreurs]:
<%
// отримання даних з шаблону
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
Вигляд [erreurs] очікує на елемент ключа «errors» у запиті. Контролер створює цей елемент у рядку 8. Він також очікує на елемент ключа «lienRetourFormulaire». Контролер створює цей елемент у рядку 9. Тут текст посилання буде порожнім. Отже, у надісланому поданні [erreurs] посилання не буде. Адже якщо під час ініціалізації додатка сталися помилки, його потрібно налаштувати заново. Немає сенсу пропонувати користувачеві продовжити роботу з додатком за допомогою посилання.
- рядки 34–37: обробка нової дії [GET /personne2/main?action=retourFormulaire]
6.6.4. Метод [doInit]
Цей метод обробляє запит № 1 [GET /personne2/main]. У відповідь на цей запит він повинен надіслати порожній вигляд [formulaire(nom,age)]. Його код такий:
- рядок 4: поточна сесія отримується, якщо вона існує, інакше створюється (параметр true з getSession).
- рядки 9–10: відображається подання [formulaire]. Нагадаємо, який шаблон очікується для цього подання:
<%
// отримання даних з моделі
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
- рядки 6–7: елементи [nom,age] моделі подання [formulaire] ініціалізуються порожніми рядками та розміщуються в сесії, оскільки саме там їх очікує подання.
- рядок 8: елемент [urlAction] моделі ініціалізується значенням параметра [urlControleur] з файлу [web.xml] і розміщується у запиті.
6.6.5. Метод [doValidationFormulaire]
Цей метод обробляє запит № 2 [POST /personne2/main], у якому передані параметри [action, txtNom, txtAge]. Його код такий:
- рядки 5–6: із запиту клієнта витягуються значення параметрів «txtNom» та «txtAge».
- рядки 8–10: ці значення зберігаються в сесії, щоб їх можна було отримати, коли користувач натисне на посилання [Retour au formulaire] у переглядах [réponse] та [erreurs].
- рядки 12–19: перевіряється правильність значень обох параметрів
- рядки 21–28: якщо один із параметрів є неправильним, відображається погляд [erreurs(erreurs,lienRetourFormulaire)]. Нагадаємо структуру цього погляду:
<%
// отримуємо дані з шаблону
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
- рядки 30–34: якщо обидва отримані параметри «txtNom» та «txtAge» мають правильні значення, відображається погляд [reponse(nom,age,lienRetourFormulaire)]. Слід згадати шаблон подання [reponse]:
<%
// отримуємо дані з моделі
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
6.6.6. Метод [doRetourFormulaire]
Цей метод обробляє запит № 3 [GET /personne2/main?action=retourFormulaire]. Його код такий:
Після виконання цього методу має відобразитися вікно [formulaire], попередньо заповнене останніми даними, введеними користувачем. Нагадаємо модель вікна [formulaire]:
<%
// отримуємо дані з шаблону
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
Отже, метод [doRetourFormulaire] повинен побудувати попередню модель.
- рядок 4: отримуємо сесію, в якій контролер зберіг введені значення (ім’я, вік).
- рядок 7: отримуємо ім’я з сесії
- рядки 8–9: якщо його там немає, додаємо його з порожнім значенням. Цей випадок не повинен траплятися під час нормальної роботи додатка, оскільки дія [retourFormulaire] завжди відбувається після дії [validationFormulaire], тобто після збереження введених даних у сесії. Однак сесія може закінчитися, оскільки має обмежений термін дії, який часто становить кілька десятків хвилин. У цьому випадку у рядку 4 створюється нова сесія, в якій імені не буде. Тоді в нову сесію вноситься порожнє ім’я.
- рядки 11–13: те саме робиться для віку
- якщо не враховувати проблему закінчення терміну дії сесії, то рядки 3–13 є зайвими. Елементи [nom,age] моделі вже знаходяться в сесії. Тому немає потреби вносити їх туди знову.
- рядок 15: встановлюємо значення елемента [urlAction] шаблону
6.7. Tests
Запустіть або перезапустіть Tomcat. Введіть URL-адресу [http://localhost:8080/personne2], а потім повторіть тести, наведені як приклад у розділі 6.1.
















