Skip to content

7. Веб-додаток MVC [personne] — версія 3


Рекомендовані матеріали в [ref1]: розділ 9


7.1. Introduction

Ми пропонуємо додати код JavaScript на сторінки HTML, що надсилаються до браузера. Саме браузер виконує код JavaScript, вбудований у сторінку, яку він відображає. Ця технологія не залежить від тієї, яку використовує веб-сервер для генерації документа HTML (Java/сервлети/JSP, ASP.NET, ASP, PHP, Perl, Python тощо).

[formulaire.jsp]

Вигляд, отриманий з цієї сторінки, буде таким:

Image

Кнопки, написи на яких виділені рамкою, використовують код JavaScript, вбудований у сторінку HTML:

Назва
Тип HTML
Функція
Submit
<submit>
виконує роль кнопки [Envoyer] з попередніх версій: надсилає введені значення до контролера
[Envoyer]
<button>
нова кнопка — локально перевіряє правильність введених даних перед їх надсиланням до контролера
Rétablir
<reset>
відновлює форму до того стану, в якому вона була спочатку отримана браузером
[Effacer]
<button>
очищає вміст обох полів введення

Ось приклад використання кнопок [Envoyer] та [Effacer]:

Ми також будемо використовувати код JavaScript для управління посиланням [Retour au formulaire] у поданнях [erreurs] та [réponse]. Розглянемо приклад подання [réponse]:

1

Різниця полягає в URL-адресі, що відображається у [1]. У попередній версії вона була такою:

[http://localhost:8080/personne2/main?action=retourFormulaire]

Тут дія більше не входить до складу URL-адреси, оскільки вона буде надіслана за допомогою POST замість GET. Ця зміна призведе до того, що єдиним URL-адресою, яка відображатиметься у браузері, буде [http://localhost:8080/personne3/main] незалежно від запитуваної дії.

7.2. Проєкт Eclipse

Щоб створити проект Eclipse [mvc-personne-03] для веб-додатка [/personne3], потрібно продублювати проект [mvc-personne-02], дотримуючись процедури, описаної в розділі 6.2 на сторінці 78.

7.3. Налаштування веб-додатку [personne3]

Файл web.xml додатка /personne3 має такий вигляд:


<?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-03</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>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-03]

Параметр [urlControleur] зник. У попередній версії він використовувався для визначення цільового об’єкта POST для подання [formulaire]. У цій новій версії цільовим об’єктом буде порожній рядок — c.a.d. URL-адреса, що відображається браузером. Ми пояснили, що вона завжди буде [http://localhost:8080/personne3/main] — саме та, яка нам потрібна для POST у поданні [formulaire].

Головна сторінка [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("/personne3/main");
%>
  • рядок 5: сторінка [index.jsp] перенаправляє клієнта на URL-адресу контролера [ServletPersonne] додатка [/personne3].

7.4. Код подання

7.4.1. Вигляд [formulaire]

Цей вигляд тепер виглядає так:

Image

Вона генерується наступною сторінкою 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");
%>


<html>
  <head>
    <title>Personne - formulaire</title>
    <script language="javascript">
        // -------------------------------
        function effacer(){
          // очищення полів введення
          with(document.frmPersonne){
            txtNom.value="";
            txtAge.value="";
          }//з
        }//очищення
        // -------------------------------      
        function envoyer(){
          // перевірка параметрів перед відправкою
          with(document.frmPersonne){
            // ім'я не повинно бути порожнім
            champs=/^\s*$/.exec(txtNom.value);
            if(champs!=null){
              // ім'я порожнє
              alert("Vous devez indiquer un nom");
              txtNom.value="";
              txtNom.focus();
              // повернення до графічного інтерфейсу
              return;
            }//if
             // вік має бути додатним цілим числом
            champs=/^\s*\d+\s*$/.exec(txtAge.value);
            if(champs==null){
              // вік вказано неправильно
              alert("Age incorrect");
              txtAge.focus();
              // повернутися до візуального інтерфейсу
              return;
            }//if
             // параметри правильні — надсилаємо їх на сервер
            submit();
          }//with
        }//надіслати
      </script>
  </head>
  <body>
    <center>
      <h2>Personne - formulaire</h2>
      <hr>
      <form name="frmPersonne" 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="Submit"></td>
            <td><input type="button" value="[Envoyer]" onclick="envoyer()"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="[Effacer]" onclick="effacer()"></td>
          </tr>
        </table>
        <input type="hidden" name="action" value="validationFormulaire">
      </form>
    </center>
  </body>
</html>


Зміни:

  • рядок 56: форма має ім’я [frmPersonne]. Це ім’я буде використовуватися в коді JavaScript. Зверніть увагу на відсутність атрибута [action], завдяки чому форма [frmPersonne] буде відправлена на URL-адресу, що відображається браузером.
  • рядок 70: кнопка [Submit] виконує роль кнопки [Envoyer] з попередніх версій
  • рядок 71: натискання кнопки [Envoyer] типу [Button] запускає виконання функції JavaScript [envoyer], визначеної в рядку 24
  • рядок 72: функція кнопки [Rétablir] не змінилася
  • рядок 73: натискання кнопки [Effacer] типу [Button] запускає функцію JavaScript [effacer], визначену в рядку 16

Перш ніж коментувати код JavaScript, нагадаємо деякі позначення:

JavaScript обробляє відображену сторінку та її вміст як дерево об’єктів, коренем якого є об’єкт [document]. У цьому документі може бути одна або кілька форм. [document.frmPersonne] позначає форму з іменем [frmPersonne], визначену в рядку 56. Ця форма також містить об’єкти. До них належать поля введення даних. Так, [document.frmPersonne.txtNom] позначає об’єкт зображення поля введення даних HTML, визначеного в рядку 60. Об’єкт [txtNom] має різні властивості, серед яких властивість [value], що позначає вміст поля введення. Таким чином, [document.frmPersonne.txtNom.value] позначає вміст поля введення [txtNom].

  • рядки 16–22: функція JavaScript [effacer] вставляє порожній рядок у поля введення [txtNom, txtAge].
  • рядки 24–49: функція JavaScript [envoyer] перевіряє правильність значень полів введення [txtNom, txtAge] перед їх відправкою. Для цього вона використовує регулярні вирази.
  • рядок 28: перевіряє, чи значення поля введення [txtNom] відповідає шаблону /s*, що означає 0 або більше пробілів. Якщо відповідь «так», це означає, що користувач не вказав ім’я. Якщо є збіг із шаблоном, змінна champs матиме значення, відмінне від покажчика null; в іншому випадку вона матиме значення null.
  • рядок 29: якщо є збіг із шаблоном
  • рядок 30: відображається повідомлення для користувача
  • рядок 32: у поле [txtNom] вноситься порожній рядок (там міг бути ряд пробілів)
  • рядок 33: курсор, що блимає, встановлюється на полі [txtNom]
  • рядок 34: функція переривається. У такому разі на сервер не надсилаються введені значення для поля POST.
  • рядки 38–45: аналогічна процедура виконується з полем [txtAge]
  • рядок 47: якщо ми дійшли до цього місця, це означає, що введені значення правильні. Тоді ми відправляємо (submit) форму [frmPersonne] на веб-сервер. Далі все відбувається так, ніби ми натиснули кнопку з написом [Submit].

7.4.2. Вигляд [reponse]

Цей вигляд відображає значення, введені у форму, якщо вони є правильними:

На відміну від попередньої версії, нововведення з’являється лише тоді, коли використовується посилання [Retour au formulaire] з вікна [réponse]:

Різниця полягає в URL-адресі, що відображається в [1]. У попередній версії вона була такою:

[http://localhost:8080/personne2/main?action=retourFormulaire]

Тут дія більше не входить до складу URL-адреси, оскільки вона буде надіслана за допомогою POST замість GET. Нова сторінка JSP [reponse.jsp] — це lqqqaaaaaaaaaqqAAAaaa

така:


<%@ 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>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      <%= lienRetourFormulaire %>
    </a>
  </body>
</html>

Нові зміни:

  • рядки 35–37: посилання [Retour au formulaire] містить JavaScript. Клік на це посилання викликає виконання JavaScript-коду з атрибута [href]. Як ми бачили під час розгляду [formulaire.jsp], ми знаємо, що цей код відправляє значення полів типу <input>, <select> тощо з форми [frmPersonne].
  • рядки 32–34: визначають форму [frmPersonne]. Вона має лише одне поле типу <input type="hidden" ...>, тобто приховане поле. Це поле [action] слугує для передачі контролеру назви дії, яку потрібно виконати, у даному випадку [retourFormulaire].

7.4.3. Вигляд [erreurs]

Цей вигляд повідомляє про помилки введення даних у формі. Зміни, внесені до нього, такі самі, як і для виду [réponse]:

Відмінність полягає в URL-адресі, що відображається у [1]. У попередній версії вона була такою:

[http://localhost:8080/personne2/main?action=retourFormulaire]

Тут дія більше не входить до складу URL-адреси, оскільки вона буде надіслана за допомогою POST замість GET. Наступна нова сторінка 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">
<%@ 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>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      <%= lienRetourFormulaire %>
    </a>
  </body>
</html>

Нововведення:

  • рядки 30–32: нове оброблення кліка на посилання. Пояснення з цього приводу, наведені в дослідженні [réponse.jsp], дійсні також і тут.

7.5. Тестування переглядів

Щоб провести тестування попередніх видів, ми дублюємо їхні сторінки JSP у папці /WebContent/JSP проекту Eclipse:

Image

Потім у папці JSP сторінки змінюються наступним чином:

[formulaire.jsp]:


...
<%
  // -- тест: створюємо шаблон сторінки
  session.setAttribute("nom","tintin");
  session.setAttribute("age","30");
%>

<%// отримуємо дані з шаблону
            String nom = (String) session.getAttribute("nom");
            String age = (String) session.getAttribute("age");
%>

Рядки 4–5 було додано для створення шаблону, необхідного для сторінки, рядки 9–10.

[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-адреси:

 

Ми отримуємо саме ті результати, на які розраховували.

7.6. Контролер [ServletPersonne]

Контролер [ServletPersonne] веб-додатку [/personne3] оброблятиме такі дії:

запит
джерело
обробка
1
[GET /personne3/main]
URL-адреса, введена користувачем
- надіслати порожній вигляд [formulaire]
2
[POST /personne3/main]
з параметрами [txtNom,
txtAge, action=validationFormulaire]
опубліковані
натискання на кнопку
[Envoyer] у вікні
[formulaire]
- перевірити значення параметрів [txtNom, txtAge]
- якщо вони неправильні, надіслати вигляд [erreurs(erreurs)]
- якщо вони правильні, надіслати вигляд [reponse(nom,age)]
3
[POST /personne3/main]
з параметрами
[action=retourFormulaire]
натиснути
натисніть на посилання [Повернутися до
форму] переглядів
[réponse] та [erreurs].
- надіслати попередньо заповнений вигляд [formulaire] з останніми введеними значеннями

Отже, у нас з’явилася нова дія, яку потрібно обробити: [POST /personne3/main] із переданим параметром [action=retourFormulaire] замість попередньої дії [GET /personne3/main?action=retourFormulaire].

7.6.1. Скелет контролера

Скелет контролера [ServletPersonne] ідентичний скелету попередньої версії.

package istia.st.servlets.personne;

...
import javax.servlet.http.HttpSession;

@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
     // параметри екземпляра
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse","lienRetourFormulaire"};
    private Map params=new HashMap<String,String>();
    ...

     // ініціалізація
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
        ...
    }

    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
...
    }

     // відображення порожньої форми
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        ...
    }

     // відображення попередньо заповненої форми
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        ...
    }

     // перевірка форми
    void doValidationFormulaire(HttpServletRequest request,
    ...
    }

     // відправка
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    ...
    }
}

Нововведення:

  • у рядку 11 масив [paramètres] більше не містить параметра [urlControleur], який було видалено з файлу [web.xml].

Методи [init, doValidationFormulaire] залишилися без змін. Методи [doGet, doInit, doRetourFormulaire] дещо змінилися.

7.6.2. Метод [doGet]

Метод [doGet] повинен обробляти дію [POST /personne3/main] із переданим параметром [action=retourFormulaire]:

    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

...
        if(méthode.equals("post") && action.equals("retourFormulaire")){
             // повернення до форми введення даних
            doRetourFormulaire(request,response);
            return;
        }
         // інші випадки
        doInit(request,response);
    }
  • рядки 6–9: обробка дії [POST /personne3/main] із переданим параметром [action=retourFormulaire]

7.6.3. Метод [doInit]

Цей метод обробляє запит № 1 [GET /personne3/main]. Його код такий:

             // відображення порожньої форми
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // отримано сесію користувача
        HttpSession session = request.getSession(true);        
         // відправлення порожньої форми
        session.setAttribute("nom", "");
        session.setAttribute("age", "");
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

Нововведення полягає в тому, що у поданні [formulaire], яке відображається у рядку 8, у моделі більше немає елемента [action].

7.6.4. Метод [doRetourFormulaire]

Цей метод обробляє запит № 1 [POST /personne3/main] із [action=retourFormulaire] у відправлених елементах. Його код такий:

     // відображення попередньо заповненої форми
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // отримано сесію користувача
        HttpSession session = request.getSession(true);        
         // чи є ім'я в сесії?
        String nom = (String) session.getAttribute("nom");
        if (nom == null)
            session.setAttribute("nom", "");
         // Чи є вік у сесії?
        String age = (String) session.getAttribute("age");
        if (age == null)
            session.setAttribute("age", "");
         // відображення форми
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

Нововведення полягає в тому, що у поданні [formulaire], яке відображається у рядку 14, у моделі більше немає елемента [action].

7.7. Tests

Запустіть або перезапустіть Tomcat після інтеграції в нього проекту Eclipse [personne-mvc-03]. Запитайте URL-адресу [http://localhost:8080/personne3], а потім повторіть тести, наведені як приклад у розділі 7.1.