Skip to content

3. Основи веб-розробки на Java

Тепер перейдемо до розробки динамічних веб-додатків, c.a.d, у яких сторінки HTML, що надсилаються користувачеві, генеруються програмами.

3.1. Створення веб-проєкту в Eclipse

Ми розробимо перший веб-додаток за допомогою Eclipse/Tomcat. Ми будемо дотримуватися підходу, аналогічного тому, що використовувався для створення веб-додатка без Eclipse. Запустивши Eclipse, ми створюємо новий проєкт:

Image

який ми визначаємо як динамічний веб-проект:

Image

На першій сторінці майстра створення вказуємо назву проєкту [1] та його розташування [2]:

Image

На другій сторінці майстра ми приймаємо значення за замовчуванням:

Image

На останній сторінці майстра нам пропонується визначити контекст [3] додатка:

Image

Після підтвердження майстра [Finish] Eclipse підключається до сайту [http://java.sun.com], щоб завантажити певні документи, які він хоче зберегти в кеші, щоб уникнути зайвих мережевих запитів. Після цього з’являється запит на підтвердження ліцензії:

Image

Ми погоджуємося. Eclipse створює веб-проект. Для його відображення використовується середовище, яке називається «перспективою» (perspective) і відрізняється від того, що використовується для класичного Java-проекту:

Image

Перспектива, пов’язана з веб-проєктом, — це J2EE. Ми її приймаємо, щоб подивитися... Отриманий результат такий:

Image

Перспектива J2EE насправді є надмірно складною для простих веб-проектів. У цьому випадку достатньо перспективи Java. Щоб її отримати, використовуємо опцію [Window -> Open perspective -> Java]:

Image

src: міститиме Java-код класів додатка, а також файли, які мають бути у Classpath додатка.

build/classes (не показано): міститиме файли .class скомпільованих класів, а також копії всіх файлів, крім .java, розміщених у src. Веб-додаток часто використовує так звані «ресурсні» файли, які повинні бути в Classpath додатка, c.a.d. Сукупність папок, які JVM обходить під час пошуку, коли додаток звертається до класу — як під час компіляції, так і під час виконання. Eclipse забезпечує, щоб папка build/classes була частиною веб-додатку. Файли «ресурсів» розміщують у папці src, знаючи, що Eclipse автоматично скопіює їх у build/classes.

WebContent: міститиме ресурси веб-додатка, які не повинні бути в Classpath цього додатка.

WEB-INF/lib: міститиме архіви .jar, необхідні веб-додатку.

Розглянемо вміст файлу [WEB-INF/web.xml], який налаштовує додаток [personne]:


<?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>    personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Ми вже стикалися з таким типом конфігурації, коли розглядали створення стартових сторінок у розділі 2.3.4. Цей файл лише визначає набір стартових сторінок. Ми залишаємо лише першу. Файл [web.xml] набуває такого вигляду:


<?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>personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Вміст наведеного вище файлу XML має відповідати правилам синтаксису, визначеним у файлі, вказаному атрибутом [xsi:schemaLocation] тегу відкриття <web-app>. У даному випадку це файл [http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd]. Це файл XML, який можна відкрити безпосередньо у веб-браузері. Якщо браузер достатньо сучасний, він зможе відобразити файл XML:

Image

Eclipse спробує перевірити валідність документа XML за допомогою файлу .xsd, вказаного в атрибуті [xsi:schemaLocation] відкриваючого тегу <web-app>. Для цього він здійснить мережевий запит. Якщо ваш комп’ютер знаходиться у приватній мережі, необхідно вказати Eclipse, який сервер використовувати для виходу з приватної мережі, так званий проксі-сервер HTTP. Це робиться за допомогою опції [Window -> Preferences -> Internet]:

Image

Поставте галочку (1), якщо ви перебуваєте у приватній мережі. У полі (2) вкажіть ім’я комп’ютера, який підтримує проксі-сервер HTTP, а в полі (3) — порт, на якому він приймає запити. Нарешті, у полі (4) вказують комп’ютери, для яких не потрібно використовувати проксі-сервер, — ті, що знаходяться в тій самій приватній мережі, що й комп’ютер, на якому ви працюєте.

Тепер ми створимо файл [index.html] для стартової сторінки.

3.2. Створення головної сторінки

Клацаємо правою кнопкою миші на папці [WebContent], а потім вибираємо опцію [New -> Other]:

Image

Ми вибираємо тип [HTML] і перетворюємо [Next] на ->

Image

Вище ми вибираємо батьківську папку [WebContent] у пункті (1) або (2), а потім у пункті (3) вказуємо ім’я файлу, який потрібно створити. Зробивши це, переходимо на наступну сторінку майстра:

Image

За допомогою (1) ми можемо створити файл HTML, попередньо заповнений даними з (2). Якщо зняти галочку з (1), буде створено порожній файл HTML. Ми залишаємо галочку біля (1), щоб отримати шаблон коду. Ми завершуємо роботу майстра, отримавши файл [Finish]. Після цього створюється файл [index.html]:

Image

з таким вмістом:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

Ми змінюємо цей файл наступним чином:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Application personne</title>
</head>
<body>
Application personne active...
<br>
<br>
Vous êtes sur la page d'accueil
</body>
</html>

3.3. Тестування головної сторінки

Якщо вона відсутня, відкриємо вікно [Servers] за допомогою опції [Window - > Show View -> Other -> Servers], а потім клацнемо правою кнопкою миші на сервері Tomcat 5.5:

Image

Зазначена вище опція [Add and Remove Objects] дозволяє додавати/видаляти веб-додатки на сервері Tomcat:

Image

Веб-проєкти, відомі Eclipse, відображаються в (1). Їх можна зареєструвати на сервері Tomcat за допомогою (2). Веб-додатки, зареєстровані на сервері Tomcat, відображаються в (4). Їх можна скасувати за допомогою (3). Зареєструємо проєкт [personne]:

Image

а потім завершимо роботу майстра реєстрації з [Finish]. У вікні [Servers] видно, що проект [personne] було зареєстровано на Tomcat:

Image

Тепер запустимо сервер Tomcat:

Запустимо веб-браузер:

Image

потім введемо URL-адресу [http://localhost:8080/personne]. Ця URL-адреса відповідає кореневому каталогу веб-додатку. Жодного документа не запитується. У цьому випадку відображається головна сторінка додатка. Якщо її немає, з’являється повідомлення про помилку. У даному випадку головна сторінка існує. Це файл [index.html], який ми створили раніше. Отримано такий результат:

Image

Він відповідає очікуваному результату. Тепер відкриємо браузер поза Eclipse та введемо той самий URL-адресу:

Image

Отже, веб-додаток [personne] також відомий поза межами Eclipse.

3.4. Створення форми HTML

Тепер створимо статичний документ HTML [formulaire.html] у папці [personne]:

Image

Для його створення слід дотримуватися процедури, описаної в розділі 3.2 на сторінці 33. Його вміст буде таким:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Personne - formulaire</title>
</head>
<body>
  <center>
    <h2>Personne - formulaire</h2>
    <hr>
    <form action="" method="post">
    <table>
      <tr>
        <td>Nom</td>
        <td><input name="txtNom" value="" type="text" size="20"></td>
      </tr>
      <tr>
        <td>Age</td>
        <td><input name="txtAge" value="" type="text" size="3"></td>
      </tr>
    </table>
    <table>
      <tr>
        <td><input type="submit" value="Envoyer"></td>
        <td><input type="reset" value="Retablir"></td>
        <td><input type="button" value="Effacer"></td>
      </tr>
    </table>
    </form>
  </center>
</body>
</html>

Наведений вище код HTML відповідає наведеному нижче бланку:

Image

тип HTML
назва
код HTML
роль
1
<input type= "text ">
txtNom
рядок 14
введення імені
2
<input type= "text ">
txtAge
рядок 18
введення віку
3
<input type= "submit ">
 
рядок 23
відправлення введених значень на сервер за адресою /personne1/main
4
<input type= "reset ">
 
рядок 24
щоб повернути сторінку до того стану, в якому вона була спочатку отримана браузером
5
<input type= "button ">
 
рядок 25
щоб очистити вміст полів введення [1] та [2]

Збережемо документ у папці <personne>/WebContent. Запустимо Tomcat, якщо це необхідно. За допомогою браузера відкриємо сторінку URL http://localhost:8080/personne/formulaire.html :

Image

Архітектура «клієнт-сервер» цього простого додатка така:

Image

Веб-сервер розташований між користувачем і веб-додатком і тут не зображений. [formulaire.html] — це статичний документ, який на кожен запит клієнта повертає однаковий вміст. Веб-програмування має на меті генерувати вміст, адаптований до запиту клієнта. Цей вміст генерується за допомогою програми. Одним із перших рішень є використання сторінки JSP (Java Server Page) замість статичного файлу HTML. Саме це ми зараз і розглянемо.

3.5. Створення сторінки JSP


Розділи [ref1]: розділ 1, розділ 2: 2.2, 2.2.1, 2.2.2, 2.2.3, 2.2.4


Попередня архітектура «клієнт/сервер» трансформується наступним чином:

Image

Сторінка JSP є варіантом сторінки HTML із заданими параметрами. Деякі елементи сторінки отримують свої значення лише під час виконання. Ці значення обчислюються програмою. Отже, ми маємо динамічну сторінку: послідовні запити до сторінки можуть призводити до різних відповідей. Під відповіддю ми тут розуміємо сторінку HTML, що відображається браузером клієнта. У підсумку браузер завжди отримує документ HTML. Цей документ HTML генерується веб-сервером на основі сторінки JSP. Остання слугує шаблоном. Її динамічні елементи замінюються їхніми фактичними значеннями на момент генерації документа HTML.

Щоб створити сторінку JSP, клацаємо правою кнопкою миші на папці [WebContent], а потім вибираємо опцію [New -> Other]:

Image

Вибираємо тип [JSP] і виконуємо [Next] ->

Image

Вище ми вибираємо батьківську папку [WebContent] у пункті (1) або (2), а потім у пункті (3) вказуємо ім’я файлу, який потрібно створити. Зробивши це, переходимо на наступну сторінку майстра:

Image

За допомогою (1) ми можемо створити файл JSP, попередньо заповнений даними з (2). Якщо зняти галочку з (1), буде створено порожній файл JSP. Ми залишаємо галочку біля (1), щоб отримати каркас коду. Ми завершуємо роботу майстра, отримавши файл [Finish]. Після цього створюється файл [formulaire.jsp]:

Image

з таким вмістом:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

Рядок 1 вказує, що ми маємо справу зі сторінкою 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=request.getParameter("txtNom");
  if(nom==null) nom="inconnu";
  String age=request.getParameter("txtAge");
  if(age==null) age="xxx";  
%>

<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title>Personne - formulaire</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire</h2>
      <hr>
      <form action="" 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>
        </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>
      </form>
    </center>
  </body>
</html>

Документ, який спочатку був статичним, тепер став динамічним завдяки введенню коду Java. Для цього типу документів ми завжди будемо діяти наступним чином:

  • вставляємо код Java на самому початку документа, щоб отримати параметри, необхідні для його відображення. Вони часто містяться в об’єкті request. Цей об’єкт представляє запит клієнта. Він може пройти через кілька сервлетів і сторінок JSP, які могли його доповнити. У даному випадку він надходить до нас безпосередньо з браузера.
  • Код HTML наведено нижче. Найчастіше він обмежується відображенням змінних, попередньо обчислених у Java-коді, за допомогою тегів <%= variable %>. Слід зауважити, що знак = стоїть безпосередньо після знака %. Це є частою причиною помилок.

Що робить попередній динамічний документ?

  • рядки 6–9: він отримує із запиту два параметри з іменами [txtNom] та [txtAge] і присвоює їхні значення змінним [nom] (рядок 6) та [age] (рядок 8). Якщо параметри не знайдено, він присвоює відповідним змінним значення за замовчуванням.
  • Він виводить значення обох змінних [nom, age] у наступному коді HTML (рядки 25 та 29).

Проведемо перше тестування. Запустимо Tomcat, якщо потрібно, а потім у браузері відкриємо сторінку URL http://localhost:8080/personne/formulaire.jsp :

Image

Документ formulaire.jsp було викликано без передачі параметрів. Тому були відображені значення за замовчуванням. Тепер запустимо URL http://localhost:8080/personne/formulaire.jsp?txtNom=martin&txtAge=14 :

Image

Цього разу ми передали документу formulaire.jsp параметри txtNom та txtAge, які він очікував. Отже, він їх відобразив. Відомо, що існує два методи передачі параметрів до веб-документа: GET та POST. В обох випадках передані параметри потрапляють до попередньо визначеного об’єкта request. У цьому випадку вони були передані методом GET.

3.6. Створення сервлету


Матеріали для читання [ref1]: розділ 1, розділ 2: 2.1, 2.1.1, 2.1.2, 2.3.1


У попередній версії запит клієнта оброблявся сторінкою JSP. Під час першого виклику цієї сторінки веб-сервер, у даному випадку Tomcat, створює на її основі клас Java та компілює його. Саме результат цієї компіляції в кінцевому підсумку обробляє запит клієнта. Клас, згенерований на основі сторінки JSP, є сервлетом, оскільки він реалізує інтерфейс [javax.Servlet]:

Image

Запит клієнта може оброблятися будь-яким класом, що реалізує цей інтерфейс. Тепер ми створюємо такий клас: ServletFormulaire. Попередня архітектура «клієнт/сервер» трансформується наступним чином:

Image

У архітектурі на основі сторінки JSP документ HTML, надісланий клієнту, був згенерований веб-сервером на основі сторінки JSP, яка слугувала шаблоном. У цьому випадку документ HTML, надісланий клієнту, буде повністю згенерований сервлетом.

3.6.1. Створення сервлета

У Eclipse клацніть правою кнопкою миші на папці [src] і виберіть опцію створення класу:

Image

потім визначимо характеристики класу, що створюється:

Image

У полі (1) вкажіть ім’я пакета, у полі (2) — ім’я класу, що створюється. Цей клас має бути похідним від класу, вказаного в полі (3). Немає потреби вводити повну назву цього класу вручну. Кнопка (4) надає доступ до класів, які наразі містяться у Classpath веб-додатку:

Image

У полі (1) вводять назву класу, який шукають. У полі (2) відображаються класи з Classpath, назва яких містить рядок, введений у полі (1).

Після підтвердження майстром створення веб-проект [personne] змінюється наступним чином:

Image

Створено клас [ServletFormulaire] із шаблоном коду:

Image

На знімку екрана вище видно, що Eclipse позначає [warning] у рядку, де оголошується клас. Клацнімо на піктограму (лампочку), що позначає цей [warning]:

Image

Після натискання на (1) у (2) пропонуються варіанти усунення помилки [warning]. Вибір одного з них призводить до появи у (3) змін у коді, які відбудуться внаслідок цього вибору.

Java 1.5 внесла зміни до мови Java, і те, що було правильним у попередній версії, тепер може викликати [warnings]. Ці повідомлення не вказують на помилки, які могли б завадити компіляції класу. Вони призначені для того, щоб привернути увагу розробника до фрагментів коду, які можна вдосконалити. Показане повідомлення [warning] вказує, що клас повинен мати номер версії. Він використовується для серіалізації/десеріалізації об’єктів, c.a.d. коли об’єкт Java .class у пам’яті потрібно перетворити на послідовність бітів, що послідовно надсилаються у потоці запису, або навпаки — коли об’єкт Java .class у пам’яті потрібно створити з послідовності бітів, що послідовно зчитуються з потоку читання. Все це дуже далеке від наших поточних завдань. Тому ми попросимо компілятор проігнорувати це попередження, вибравши варіант [Add @SuppressWarnings ...]. Тоді код виглядатиме так:

Image

[warning] більше немає. Доданий рядок називається «анотацією» — поняттям, що з’явилося в Java 1.5. Ми доповнимо цей код пізніше.

3.6.2. Classpath проекту Eclipse

Classpath Java-додатка — це сукупність папок та archives.jar, які переглядаються під час компіляції додатка або під час його виконання. Ці два Classpath не обов’язково збігаються, оскільки деякі класи потрібні лише під час виконання, а не під час компіляції. Як компілятор Java, так і JVM мають аргумент, що дозволяє вказати Classpath додатка, який потрібно скомпілювати або виконати. Більш-менш прозоро для користувача Eclipse забезпечує формування та передачу цього аргументу до JVM.

Як дізнатися про елементи Classpath проекту Eclipse? За допомогою опції [<projet> / Build Path / Configure Build Path]:

Image

У результаті ми отримуємо такий майстер налаштування:

Image

Вкладка (1) [Libraries] дозволяє визначити список архівів .jar, що входять до складу Classpath додатка. Отже, вони скануються JVM, коли додаток запитує клас. Кнопки [2] та [3] дозволяють додавати архіви до Classpath. Кнопка [2] дозволяє вказати архіви, що знаходяться в папках проектів, якими керує Eclipse, тоді як кнопка [3] дозволяє вказати будь-який архів у файловій системі комп’ютера.

Вище відображаються три бібліотеки (Libraries):

  • [JRE System Library]: базова бібліотека для Java-проектів Eclipse:

Image

  • [Tomcat v5.5 runtime]: бібліотека, що надається сервером Tomcat. Вона містить класи, необхідні для веб-розробки. Ця бібліотека включається до кожного веб-проєкту Eclipse, пов’язаного із сервером Tomcat.

Image

Саме архів [servlet-api.jar] містить клас [javax.servlet.http.HttpServlet], який є батьківським класом для класу [ServletFormulaire], що ми зараз створюємо. Саме тому, що цей архів знаходиться в Classpath додатка, його було запропоновано як батьківський клас у майстрі, зображеному нижче.

Image

Якби це не було так, він не з’явився б у списку пропозицій для [2]. Отже, якщо в цьому майстрі потрібно вказати батьківський клас, а його немає серед пропозицій, це означає, що або ви помилилися в назві цього класу, або архів, що його містить, відсутній у Classpath додатка.

  • [Web App Libraries] містить архіви, що знаходяться в папці [WEB-INF/lib] проекту. Тут вона порожня:

Image

Архіви з папки Classpath проекту Eclipse відображаються у провіднику проектів. Наприклад, для веб-проекту [personne]:

Image

Оглядач проєктів надає доступ до вмісту цих архівів:

Image

Отже, як показано вище, саме архів [servlet-api.jar] містить клас [javax.servlet.http.HttpServlet].

3.6.3. Налаштування сервлету


Матеріали [ref1]: розділ 2: 2.3, 2.3.1, 2.3.2, 2.3.3, 2.3.4


Файл [WEB-INF/web.xml] використовується для налаштування веб-додатку:

Image

Цей файл для проєкту [personne] наразі має такий вигляд (див. стор. 32):


<?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>personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

У ньому вказано лише наявність файлу-початкової сторінки (рядок 8). Ми модифікуємо його, щоб вказати:

  • наявність сервлету [ServletFormulaire]
  • URL, що обробляються цим сервлетом
  • параметри ініціалізації сервлета

Файл web.xml нашого додатка «особа» матиме такий вигляд:


<?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>personne</display-name>
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Основні моменти цього конфігураційного файлу такі:

  • рядки 7–24 пов’язані з наявністю сервлета [ServletFormulaire]
  • рядки 7–20: налаштування сервлета здійснюється між тегами <servlet> та </servlet>. Додаток може містити кілька сервлетів і, відповідно, стільки ж розділів налаштування <servlet>...</servlet>.
  • рядок 8: тег <servlet-name> присвоює сервлету ім’я — воно може бути будь-яким
  • рядки 9–11: тег <servlet-class> вказує повну назву класу, що відповідає сервлету. Tomcat шукатиме цей клас у файлі Classpath веб-проєкту [personne]. Він знайде його у файлі [build/classes]:

Image

  • рядки 12–15: тег <init-param> слугує для передачі параметрів конфігурації сервлету. Зазвичай вони зчитуються у методі init сервлету, оскільки параметри його конфігурації мають бути відомі вже під час першого завантаження.
  • рядки 13–14: тег <param-name> визначає ім’я параметра, а <param-value> — його значення.
  • рядки 12–15 визначають параметр [defaultNom,"inconnu"], а рядки 16–19 — параметр [defaultAge,"XXX"]
  • рядки 21–24: тег <servlet-mapping> слугує для прив’язки сервлету (servlet-name) до шаблону URL (url-pattern). У цьому випадку шаблон є простим. Він визначає, що щоразу, коли URL матиме вигляд /formulaire, слід використовувати сервлет formulairepersonne, c.a.d. клас [istia.st.servlets.ServletFormulaire] (рядки 8–11). Отже, сервлет [formulairepersonne] приймає лише один URL-адресу.

3.6.4. Код сервлета [ServletFormulaire]

Сервлет [ServletFormulaire] матиме такий код:

package istia.st.servlets.personne;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ServletFormulaire extends HttpServlet {

     // параметри екземпляра
    private String defaultNom = null;
    private String defaultAge = null;

     // ініціалізація
    public void init() {
         // отримуємо параметри ініціалізації сервлета
        ServletConfig config = getServletConfig();
        defaultNom = config.getInitParameter("defaultNom");
        if (defaultNom == null)
            defaultNom = "NNNNNNNNNNNNNNN";
        defaultAge = config.getInitParameter("defaultAge");
        if (defaultAge == null)
            defaultAge = "AAA";
    }

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // отримуємо параметри форми
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
         // відображаємо форму
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println(
                "<html>"+
                  "<head>"+
                    "<title>Personne - formulaire</title>"+
                  "</head>"+
                  "<body>"+
                    "<center>"+
                      "<h2>Personne - formulaire</h2>"+
                      "<hr>"+
                      "<form action='' 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>"+
                        "</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>"+
                      "</form>"+
                    "</center>"+
                  "</body>"+
                "</html>"
      );
    }

     // POST
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // передаємо управління GET
        doGet(request, response);
    }
}

Вже при першому ознайомленні з сервлетом можна помітити, що він набагато складніший за відповідну сторінку JSP. Це загальне правило: сервлет не призначений для генерації коду HTML. Для цього призначені сторінки JSP. Ми ще повернемося до цього питання. Роз’яснимо кілька важливих моментів щодо наведеного вище сервлету:

  • коли сервлет викликається вперше, викликається його метод init (рядок 20). Це єдиний випадок, коли він викликається.
  • якщо сервлет було викликано методом HTTP GET, викликається метод doGet (рядок 32) для обробки запиту клієнта.
  • якщо сервлет був викликаний методом HTTP POST, то для обробки запиту клієнта викликається метод doPost (рядок 82).

Метод init тут використовується для отримання у [web.xml] значень параметрів ініціалізації, що називаються «defaultNom» та «defaultAge». Метод init, що виконується під час початкового завантаження сервлета, є оптимальним місцем для отримання вмісту файлу [web.xml].

  • рядок 22: отримується конфігурація [config] веб-проєкту. Цей об’єкт відображає вміст файлу [WEB-INF/web.xml] додатка.
  • рядок 23: з цієї конфігурації отримується значення типу String параметра з назвою «defaultNom». Цим параметром буде ім’я особи. Якщо він не існує, буде отримано значення null.
  • рядки 24–25: якщо параметр із назвою «defaultNom» не існує, змінній [defaultNom] присвоюється значення за замовчуванням.
  • рядки 26–29: те саме робимо для параметра з назвою «defaultAge».

Метод doPost посилається на метод doGet. Це означає, що клієнт може надсилати свої параметри як за допомогою POST, так і за допомогою GET.

Метод doGet:

  • рядок 32: метод отримує два параметри — request та response. request — це об’єкт, що представляє весь запит клієнта. Він має тип HttpServletRequest, який є інтерфейсом. response має тип HttpServletResponse, який також є інтерфейсом. Об’єкт response слугує для надсилання відповіді клієнту.
  • request.getParameter("param") використовується для отримання у запиті клієнта значення параметра з іменем param. У рядку 36 отримуємо значення параметра «txtNom», у рядку 40 — значення параметра «txtAge». Якщо ці параметри відсутні у запиті, як значення параметра отримується null.
  • рядки 37–39: якщо параметр «txtNom» відсутній у запиті, змінній «nom» присвоюється ім’я за замовчуванням «defaultNom», ініціалізоване в методі init. Те саме робиться в рядках 41–43 для віку.
  • рядок 45: response.setContentType(String) слугує для встановлення значення заголовка HTTP Content-type. Цей заголовок вказує клієнту на тип документа, який він отримає. Тип text/html вказує на документ HTML.
  • рядок 46: response.getWriter() служить для отримання потоку запису до клієнта
  • рядки 47–78: документ HTML, який потрібно надіслати клієнту, записується у потік запису, отриманий у рядку 46.

Компіляція цього сервлета створить файл .class у папці [build/classes] проекту [personne]:

Image

Читачеві рекомендується ознайомитися з довідкою Java щодо сервлетів. Для цього можна скористатися Tomcat. На сторінці входу в Tomcat 5 є посилання [Documentation]:

Image

Це посилання веде на сторінку, яку читачеві пропонується переглянути. Посилання на документацію щодо сервлетів таке:

Image

3.6.5. Тестування сервлета

Ми готові до тестування. Запустимо сервер Tomcat, якщо це необхідно.

Image

Потім за допомогою браузера звернемося до URL [http://localhost:8080/personne/formulaire]. Тут ми звертаємося до URL-адреси [/formulaire] у контексті [/personne]. Файл [web.xml] цього контексту вказує, що URL-адреса [/formulaire] обробляється сервлетом із назвою [formulairepersonne]. У тому ж файлі вказано, що цей сервлет є класом [istia.st.servlets.ServletFormulaire]. Отже, саме цьому класу Tomcat доручить обробку запиту клієнта. Якщо клас ще не завантажено, його буде завантажено. Після цього він залишиться в пам’яті для обробки майбутніх запитів.

За допомогою вбудованого в Eclipse браузера отримуємо такий результат:

Image

Ми отримуємо значення імені та віку за замовчуванням, які записані у файлі [web.xml]. Тепер спробуємо отримати URL та [http://localhost:8080/personne/formulaire?txtNom=tintin&txtAge=30]:

Image

Цього разу ми отримуємо параметри, передані у запиті. Якщо читач не розуміє цих двох результатів, йому слід ще раз перечитати код сервлету [ServletFormulaire].

3.6.6. Автоматичне оновлення контексту веб-додатку

Запустимо Tomcat:

Image

а потім змінимо код сервлета наступним чином:

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // отримуємо параметри форми
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = "--"+defaultNom+"--";
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
...
  • рядок 8 було змінено

Збережемо новий клас. Це збереження призведе до того, що Eclipse автоматично перекомпілює клас [ServletFormulaire], що буде виявлено Tomcat. Потім він перезавантажить контекст веб-додатку [personne], щоб врахувати зміни. Це відображається в журналах вікна [console]:

Image

Запросімо URL-адресу [http://localhost:8080/personne/formulaire] без перезапуску Tomcat:

Image

Зміни були успішно застосовані.

Тепер змінимо файл [web.xml] наступним чином:


<?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>personne</display-name>
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
...
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>INCONNU</param-value>
        </init-param>
...
    </servlet>
...
</web-app>
  • рядок 12 було змінено

Зробивши це, збережемо новий файл [web.xml]. У вікні [console] немає жодних записів у журналі, що вказують на перезавантаження контексту додатка. Запросимо URL-адресу [http://localhost:8080/personne/formulaire] без перезапуску Tomcat:

Image

Зміни не були враховані. Перезапустимо Tomcat [clic droit sur serveur -> Restart -> Start]:

Image

потім знову звернемося за URL-адресою [http://localhost:8080/personne/formulaire]:

Image

Цього разу зміна, внесена в [web.xml], відображається.

Отже, зміна у файлі [web.xml] не спричиняє автоматичного перезавантаження веб-додатку, яке врахувало б новий файл конфігурації. Щоб примусово перезавантажити веб-додаток, можна перезапустити Tomcat, як ми це робили раніше, але це досить повільна операція. Краще скористатися інструментом [manager] для адміністрування додатків, розгорнутих у Tomcat. Щоб це стало можливим, у середовищі Eclipse Tomcat має бути налаштований так, як показано в розділі 2.5.

Спочатку за допомогою вбудованого браузера Eclipse відкрийте URL-адресу [http://localhost:8080], а потім перейдіть за посиланням [Tomcat Manager], як описано наприкінці розділу 2.5:

Image

Відкриємо другий браузер [clic droit sur le navigateur -> New Editor]:

У цьому другому браузері введемо URL-адресу [http://localhost:8080/formulaire]:

Image

Змінимо файл [web.xml] наступним чином, а потім збережемо його:


<!--   ServletFormulaire -->
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>YYY</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>

Потім знову завантажимо URL-адресу [http://localhost:8080/formulaire]. Ми бачимо, що зміна не була врахована. Тепер перейдемо до першого браузера та перезавантажимо додаток [personne]:

Image

Потім знову завантажимо URL-адресу [http://localhost:8080/formulaire] у другому браузері:

Image

Зміна [web.xml] була врахована. На практиці для вирішення подібних випадків корисно мати відкритий браузер із додатком [manager] у Tomcat.

3.7. Взаємодія сервлетів та сторінок JSP


Література [ref1]: розділ 2: 2.3.7


Повернемося до двох розглянутих архітектур:

Image

Жодна з цих двох архітектур не є задовільною. Обидві мають недолік, що поєднують дві технології: технологію програмування на Java, яка відповідає за логіку веб-додатку, та технологію кодування HTML, яка відповідає за відображення інформації у браузері.

  • Рішення [1] на основі сторінки JSP має недолік, що поєднує код HTML та код Java в межах однієї сторінки. Ми цього не помітили на розглянутому прикладі, який був досить простим. Але якби [formulaire.jsp] мав перевіряти валідність параметрів [txtNom, txtAge] у запиті клієнта, нам довелося б розміщувати код Java на сторінці. Це дуже швидко стає некерованим.
  • Рішення [2] на основі сервлета має ту саму проблему. Хоча в класі міститься лише код Java, він повинен генерувати документ HTML. І знову ж таки, якщо документ HTML не є простим, його генерація стає складною і практично неможливою для підтримки.

Ми уникнемо змішування технологій Java та HTML, застосувавши таку архітектуру:

Image

  • користувач надсилає свій запит до сервлету. Сервлет обробляє його та формує значення динамічних параметрів сторінки JSP [formulaire.jsp], які будуть використовуватися для формування відповіді HTML для клієнта. Ці значення утворюють так звану модель сторінки JSP.
  • Завершивши свою роботу, сервлет звернеться до сторінки JSP [formulaire.jsp] із запитом на формування відповіді HTML для клієнта. Одночасно вона надасть клієнту елементи, необхідні сторінці JSP для формування цієї відповіді — саме ці елементи і складають модель сторінки.

Тепер ми розглянемо цю нову архітектуру.

3.7.1. Сервлет [ServletFormulaire2]

У наведеній вище архітектурі сервлет матиме назву [ServletFormulaire2]. Він буде створений у тому самому проєкті [personne], що й раніше, так само як і всі майбутні сервлети:

Image

[ServletFormulaire2] спочатку створюється шляхом копіювання та вставлення [ServletFormulaire] у середовищі Eclipse:

  • виділити [ServletFormulaire.java] -> клацнути правою кнопкою миші -> «Копіювати»
  • виділити [istia.st.servlets.personne] -> клацнути правою кнопкою миші -> Вставити -> змінити ім’я на [ServletFormulaire2.java]

Потім ми змінюємо код [ServletFormulaire2] наступним чином:

package istia.st.servlets.personne;

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ServletFormulaire2 extends HttpServlet {

     // параметри екземпляра
    private String defaultNom = null;

    private String defaultAge = null;

     // ініціалізація
    public void init() {
         // отримуємо параметри ініціалізації сервлета
        ServletConfig config = getServletConfig();
        defaultNom = config.getInitParameter("defaultNom");
        if (defaultNom == null)
            defaultNom = "NNNNNNNNNNNNNNN";
        defaultAge = config.getInitParameter("defaultAge");
        if (defaultAge == null)
            defaultAge = "AAA";
    }

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // отримуємо параметри форми
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
         // відображаємо форму
        request.setAttribute("nom", nom);
        request.setAttribute("age", age);
        getServletContext().getRequestDispatcher("/formulaire2.jsp").forward(request, response);
    }

     // POST
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // передаємо управління GET
        doGet(request, response);
    }
}

Змінилася лише частина, що відповідає за формування відповіді HTTP (рядки 44–46):

  • рядок 46: формування відповіді доручено сторінці JSP formulaire2.jsp. Ця сторінка, яку ми ще не розглядали, відповідатиме за відображення параметрів, отриманих із запиту клієнта: імені (рядки 35–38) та віку (рядки 39–42).
  • Ці два значення розміщуються в атрибутах запиту [request], пов’язаних із ключами. Атрибути запиту обробляються як словник.
  • рядок 44: ім’я вноситься до запиту, пов’язаного з ключем «ім’я»
  • рядок 45: вік вноситься до запиту, пов’язаного з ключем «age»
  • рядок 46: запит на відображення сторінки JSP [formulaire2.jsp]. До неї передаються такі параметри:
  • запит [request] від клієнта, що дозволить сторінці JSP отримати доступ до її атрибутів, які щойно були ініціалізовані сервлетом
  • відповідь [response], що дозволить сторінці JSP згенерувати відповідь HTTP для клієнта

Після написання класу [ServletFormulaire2] його скомпільований код з’являється у [build/classes]:

Image

3.7.2. Сторінка JSP [formulaire2.jsp]

Сторінка JSP formulaire2.jsp отримується шляхом копіювання та вставлення зі сторінки [formulaire.jsp]

Image

а потім перетворено таким чином:


<%@ 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>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title>Personne - formulaire2</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire2</h2>
      <hr>
      <form action="" 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>
        </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>
      </form>
    </center>
  </body>
</html>

Порівняно з [formulaire.jsp] змінилися лише рядки 4–8:

  • рядок 6: отримує значення атрибута з назвою «nom» із запиту [request], атрибут, створений сервлетом [ServletFormulaire2].
  • рядок 7: робить те саме для атрибута «age»

3.7.3. Налаштування додатка

Файл конфігурації [web.xml] змінюється наступним чином:


<?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>personne</display-name>
    <!--  ServletFormulaire -->
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXXX</param-value>
        </init-param>
    </servlet>
     <!--  ServletFormulaire 2-->
    <servlet>
        <servlet-name>formulairepersonne2</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire2
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>
    <!--  Мапування ServletFormulaire -->
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
     <!--  Відповідність ServletFormulaire 2-->
    <servlet-mapping>
        <servlet-name>formulairepersonne2</servlet-name>
        <url-pattern>/formulaire2</url-pattern>
    </servlet-mapping>
    <!--  файли-шаблони -->
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Ми зберегли існуючий код та додали:

  • рядки 22–36: розділ <servlet> для визначення нового сервлета ServletFormulaire2
  • рядки 42–46: розділ <servlet-mapping> для прив’язки до нього URL /formulaire2

Запустіть або перезапустіть сервер Tomcat, якщо це необхідно. Ми запитуємо URL

http://localhost:8080/personne/formulaire2?txtNom=milou&txtAge=10:

Image

Ми отримуємо той самий результат, що й раніше, але структура нашого додатка тепер стала чіткішою: сервлет, що містить логіку додатка та делегує сторінці JSP відправку відповіді клієнту. Відтепер ми завжди будемо діяти саме так.