Skip to content

6. Форми HTML

До цього моменту ми використовували єдину форму, що містила лише два поля введення. Тут ми пропонуємо створити та обробити форму, використовуючи звичайні графічні компоненти (перемикачі, прапорці, поля введення, комбіновані списки, списки).

6.1. Види додатка

Додаток матиме лише два види. Перший відображає порожню форму:

QZXW2HTMLP000547ZQX 1 - formulaire

Image

Цей перший вигляд, який називається formulaire.jsp, дозволить нам реалізувати різні теги з бібліотеки struts-html. Користувач заповнює форму:

Image

Кнопка [Envoyer] дозволяє отримати підтвердження введених значень. Це буде другий екран:

Image

Цей другий вигляд дозволить нам використовувати ще дві бібліотеки тегів — struts-bean та struts-logic. Посилання [Retour au formulaire] дозволяє повернутися до форми в тому вигляді, в якому її було заповнено. Ми знову потрапляємо на перший вигляд.

6.2. Архітектура додатка

  • Форма (представлення 1) буде представлена динамічним об’єктом Struts під назвою dynaFormulaire, тип якого походить від DynaActionForm. Вона відображатиметься за допомогою представлення formulaire.jsp.
  • Дія Struts InitFormulaireAction призначена для отримання даних, необхідних для відображення форми
  • заповнена форма буде оброблена дією ForwardAction, яка лише перенаправить запит до другого виду confirmation.jsp. Цей вид відповідатиме за відображення значень форми.

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

6.3.1. Файл server.xml

Контекст додатка матиме назву /formulaire2. Тому до файлу server.xml у Tomcat додамо такий рядок:

    <Context path="/formulaire2" docBase="e:/data/serge/web/struts/formulaire2" />

Після цього, за необхідності, перезапустимо Tomcat, щоб він врахував новий контекст. Ми можемо перевірити його правильність, звернувшись до URL http://localhost:8080/formulaire2 :

Image

6.3.2. Файл web.xml

Файл конфігурації web.xml додатка матиме такий вигляд:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <servlet>
      <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
      <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
  </taglib>

</web-app>

Щодо конфігураційних файлів web.xml, з якими ми вже стикалися, ми вносимо кілька змін:

  • ми додаємо дві нові бібліотеки тегів — struts-bean та struts-logic. Вони будуть використовуватися у подачі confirmation.jsp. Подача formulaire.jsp, у свою чергу, використовуватиме бібліотеку struts-html.

6.3.3. Файл struts-config.xml

Файл struts-config.xml матиме такий вигляд:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
    <form-beans>
        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                  
        </form-bean>            
    </form-beans>

    <action-mappings>
      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

    </action-mappings>

        <message-resources 
      parameter="ApplicationResources"
        null="false"/>    

</struts-config>

Тут містяться три основні розділи:

  • опис форм у розділі <form-beans>
  • описання дій у розділі <action-mappings>
  • описання файлу ресурсів у розділі <message-ressources>

6.3.4. Об’єкти (біни) форм додатка

Об’єкти, що використовуються для представлення форм HTML у додатку, є об’єктами типу ActionForm або його похідними (DynaActionForm, DynaValidatorForm, ...). Їх називають «бінами», оскільки їхня побудова відповідає правилам JavaBeans. У нашому додатку є лише один «бін» форми, який називається dynaFormulaire і є похідним від типу DynaActionForm. Він використовуватиметься в таких ситуаціях:

  • для зберігання даних, необхідних для відображення подання № 1
  • отримувати значення з форми виду № 1, коли користувач підтвердить її (submit)
  • містити дані, необхідні для відображення виду № 2

Структура біна dynaFormulaire тісно пов’язана з формою подання № 1. Розглянемо її:

Тип HTML
Роль
1
<input name="opt" type="radio" value="так">
<input name="opt" type="radio" value="ні">
група пов'язаних між собою перемикачів (однакова назва)
2
<input name="chk1" type="radio" value="on">
<input name="chk2" type="radio" value="on">
<input name="chk3" type="radio" value="on">
групи прапорців
(не однакові назви)
3
<input type="text" name="champSaisie" >
поле введення
4
<input type="password " name="mdp" >
поле для введення пароля
5
<textarea name="boiteSaisie">...</textarea>
поле для введення тексту з кількома рядками
6
<select name="combo" size="1">..</select>
список
7
<select name="listeSimple" size="3">..</select>
список з одним варіантом вибору
8
<select name="listeMultiple" size="3" multiple>..</select>
список із можливістю вибору декількох елементів
9
<input type="button" value="Очистити"
onclick='effacerListe("listeSimple")'>
кнопка для скасування вибору
вибрані елементи в listeSimple (7)
10
<input type="button" value="Очистити"
onclick='effacerListe("listeMultiple")'>
кнопка, що дозволяє скасувати вибір
вибраних елементів у listeMultiple (8)
11
<input type="submit" value="Надіслати">
кнопка відправки форми
12
<input type="hidden" name="secret" value="...">
приховане поле

Розрізнимо кілька випадків:

  1. об'єкт dynaFormulaire використовується для зберігання значень форми HTML, наведеної вище, яка буде відправлена за допомогою кнопки [Envoyer]. Тому він повинен мати ті самі поля, що й у формі HTML. Тип поля визначається за таким правилом:
  • якщо поле HTML надає лише одне значення, то поле dynaFormulaire матиме тип java.lang.String
  • якщо поле HTML містить кілька значень, то поле dynaFormulaire матиме тип java.lang.String[]

У наведеному вище бланку HTML лише поле listeMultiple може бути пов’язане з кількома значеннями (вибраними користувачем). Отже, перше визначення об’єкта dynaFormulaire буде таким:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
        </form-bean>            

Як відбуватиметься заповнення поля dynaFormulaire значеннями з форми HTML, надісланими веб-клієнтом?

opt
поле opt отримає значення «так», якщо було позначено поле HTML <input type="radio" name="opt" value="так">, і значення «ні», якщо було позначено поле <input type="radio" name="opt" value="ні">.
chk1
поле chk1 отримає значення «on», якщо було позначено поле HTML <input name="chk1" type="radio" value="1">, інакше — ні. В останньому випадку поле chk1 збереже своє попереднє значення.
chk2
те саме
chk3
те саме
champSaisie
поле champSaisie отримає текст, введений користувачем у полі HTML <input type="text" name="champSaisie">. Цей текст може бути порожнім рядком.
mdp
поле mdp отримає текст, введений користувачем у полі HTML <input type="password" name="mdp">. Цей текст може бути порожнім.
boiteSaisie
У поле boiteSaisie буде введено текст, який користувач ввів у поле HTML <textarea name="boiteSaisie">...</textarea>. Цей текст утворює єдиний рядок, що складається з рядків, введених користувачем, розділених між собою послідовністю символів «\r\n». Отриманий текст може бути порожнім рядком.
combo
поле комбінованого списку отримає опцію, вибрану користувачем у полі HTML <select name="combo" size="1">..</select>. Вибраною вважається та опція, яка відображається у комбінованому списку. Якщо вибраний варіант HTML має тип <option value="XX">YY</option>, поле комбінованого списку отримає значення «XX». Якщо вибрана опція HTML має тип <option>YY</option>, поле зі списком отримає значення «YY».
listeSimple
поле listeSimple отримає опцію, обрану користувачем у полі HTML <select name="listeSimple" size="..">..</select>, якщо така є. Якщо її немає, поле listeSimple не отримає жодного значення і збереже своє попереднє значення. Значення, яке фактично присвоюється полю listeSimple, відповідає правилам, зазначеним для комбінованого списку.
listeMultiple
поле listeMultiple типу String[] отримає опції, вибрані користувачем у полі HTML <select name="listeMultiple" size=".." multiple>..</select>, якщо такі є. Якщо їх немає, масив listeMultiple не отримає жодного значення, і його вміст залишиться незмінним. Значення, що фактично присвоюються масиву listeMultiple, відповідають правилам, зазначеним для комбінованого списку.
secret
поле secret отримає значення XX з поля HTML <input type="hidden" name="secret" value="XX">. Цей текст може бути порожнім рядком.
  1. Об’єкт dynaFormulaire використовується для надання початкового вмісту подання № 1. Значення попередніх полів будуть використовуватися для таких цілей:
opt
повинен мати значення «так» або «ні», щоб браузер знав, яку опцію потрібно вибрати
chk1
якщо chk1 має значення «on», то поле буде позначено, інакше — ні
chk2
те саме
chk3
те саме
champSaisie
значення поля буде відображено в полі введення champSaisie
mdp
значення поля буде відображено в полі введення пароля
boiteSaisie
значення поля буде відображено в полі введення boiteSaisie
combo
значення цього поля вказує, який елемент комбінованого списку має бути вибраний під час відображення форми
listeSimple
те саме
listeMultiple
значення таблиці listeMultiple вказують, які елементи списку з кількома варіантами мають бути вибрані під час відображення форми
secret
значення поля буде присвоєно атрибуту value поля HTML secret.

Вид № 1 потребує додаткової інформації:

  • список значень, які потрібно відобразити у комбінованому списку
  • список значень, які потрібно відобразити у списку listeSimple
  • список значень, які потрібно відобразити у списку listeMultiple

Існує кілька способів передати цю інформацію до подання. Наприклад, для цього підійдуть масиви, розміщені у запиті, що передається до подання. У цьому випадку ми розміщуємо ці масиви у біні dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                  
        </form-bean>            

Форма dynaFormulaire буде ініціалізована дією /init, яка викличе об’єкт, похідний від Action, під назвою InitFormulaireAction. Саме цей об’єкт буде відповідати за створення трьох масивів, необхідних для відображення трьох списків, та їх розміщення у біні dynaFormulaire. Файл конфігурації надає цьому bean-у область дії, що дорівнює сесії. Це означає, що контролер Struts розмістить цей bean у сесії. Таким чином, нам не доведеться його перегенерувати між двома циклами «запит-відповідь». Отже, дія /init буде викликана лише один раз.

  1. Об’єкт dynaFormulaire також використовується для надання вмісту подання № 2. Воно лише відображає його значення.

6.3.5. Дії додатка

Дії виконуються об’єктами типу Action або його похідними. Налаштування дій здійснюється всередині тегів <action-mappings>:

    <action-mappings>
      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

    </action-mappings>

Зауважимо, що не завжди до дії прив’язана форма. Це стосується, зокрема, дії /affiche, наведеної вище. Перш ніж детально розглянути кожну дію, нагадаємо, як працює пара «дія-форма» у тезі <action>:

  • дія починається із запиту від веб-клієнта і завершується відправленням сторінки-відповіді. Це цикл «запит-відповідь» між веб-клієнтом і веб-сервером. Запит приймається контролером Struts типу ActionServlet або його похідним. Цей самий контролер і відправляє відповідь.
  • біан форми типу ActionForm або його похідного створюється, якщо його ще не існує. Контролер перевіряє, чи може він знайти об’єкт з іменем name у області дії, вказаній атрибутом scope. Якщо так, він використовує його. Якщо ні, він створює його та розміщує в області дії, вказаній атрибутом scope, пов’язавши з атрибутом, вказаним атрибутом name.

Наприклад, у випадку дії /init контролер виконає виклик request.getSession().getAttribute("dynaFormulaire"), щоб перевірити, чи об’єкт dynaFormulaire вже створено. Якщо це не так, він створить його та додасть до сесії за допомогою інструкції на кшталт request.getSession().setAttribute("dynaFormulaire", new DynaFormulaire(...)).

  • Контролер також шукатиме об’єкт Action типу, вказаного атрибутом type. Якщо він його не знайде, то створить його, інакше — використає.
  • Буде викликано метод reset біна форми. Цей бін, за винятком моменту його початкового створення, піддається рециркуляції. Отже, він містить дані, які, можливо, потрібно «очистити». Це робиться в методі reset біна ActionForm або його похідного.
  • якщо дія є ціллю відправленої форми, то значення форми, що містяться у запиті клієнта, копіюються в поля з відповідними іменами у біні форми. Слід зауважити, що перед цим копіюванням було викликано метод reset.
  • Якщо в конфігурації вказано атрибут `validate="true"`, буде викликано метод `validate` біна форми. Цей метод повинен перевірити дані біна. Така перевірка найчастіше відбувається лише тоді, коли форма щойно отримала нові дані через відправлену форму і потрібно перевірити їхню правильність. Цей метод повертає контролеру можливий список помилок у об’єкті ActionErrors.
  • Якщо об’єкт ActionErrors не порожній, контролер відображає представлення, вказане атрибутом input дії.
  • якщо перевірка даних не вимагається або якщо вона пройшла успішно, контролер запускає метод execute об’єкта типу Action або його похідного, пов’язаного з поточною дією. Саме в цьому методі обробляється запит веб-клієнта. Метод execute повертає об’єкт ActionForward, індексований ключами типу символьного рядка. Ці ключі — це ті, що оголошені тегами forward налаштованої дії. У нашому прикладі дія /init має лише один тег forward. Він пов’язує ключ «afficherFormulaire» із видом formulaire.jsp.
  • контролер відображає вигляд, якому відповідає отриманий ключ. Цей вигляд може бути, власне, дією, і в цьому випадку попередній процес повторюється.

Дія /init

        <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>
  • Дія /init зазвичай виконується один раз під час першого циклу «запит-відповідь», коли користувач запитує URL http://localhost:8080/formulaire2/init.do
  • об’єкт dynaFormulaire створюється або повторно використовується. Він підбирається (повторне використання) або розміщується (створення) у сесії відповідно до атрибута scope.
  • Викликається його метод reset. Що він повинен зробити? Зазвичай поля об’єкта ActionForm скидаються до значень за замовчуванням. Однак у цьому випадку ми цього не зробимо, оскільки об’єкт dynaFormulaire розміщується в сесії (scope="session"). Отже, поля dynaFormulaire повинні зберегти свої значення. Якими є ці значення під час початкового створення об’єкта dynaFormulaire? Існують два випадки:
  • поле має початкове значення, вказане у файлі конфігурації:
            <form-property name="opt" type="java.lang.String" initial="non"/>

У цьому випадку контролер Struts створить це поле з цим початковим значенням.

  • поле не має початкового значення за конфігурацією: застосовуються правила ініціалізації Java. Як правило, числові поля матимуть значення нуль, символьні рядки — порожній рядок, а інші об’єкти — значення null.

Розглянемо початкову конфігурацію dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>             
        </form-bean>            

Початкові значення полів dynaFormulaire після його створення будуть такими:

Поле
Початкове значення
opt
«ні»
chk1, chk2, chk3
порожній рядок
champSaisie
порожній рядок
mdp
порожній рядок
boiteSaisie
порожній рядок
combo
порожній рядок
listeSimple
порожній рядок
listeMultiple
масив порожніх рядків
secret
"xxx"
valeursCombo, listeSimple, listeMultiple
масив порожніх рядків
  • можна уявити, що метод reset класу dynaFormulaire присвоює значення трьом масивам, які мають заповнювати три списки у поданні formulaire.jsp. Це було б можливо в даному випадку, оскільки дані цих трьох масивів генеруються довільним чином. Проте найчастіше ці дані походять із моделі додатка, тобто з M у MVC. Тут ми оберемо проміжний варіант, щоб не ускладнювати приклад, і згенеруємо ці значення за допомогою дії InitFormulaireAction, тобто за допомогою C з MVC.
  • Немає обов’язку писати метод reset у dynaFormulaire, оскільки клас ActionForm, від якого він походить, має такий метод, який нічого не робить (не виконує ініціалізацій).
  • Після виклику методу reset класу dynaFormulaire контролер перевіряє атрибут validate дії. У цьому випадку він має значення «false». Метод validate класу dynaFormulaire не буде викликаний.
  • Об’єкт InitFormulaireAction створюється або переробляється, якщо він уже існував, і запускається його метод `execute`. Саме цей метод присвоїть довільні значення трьом масивам dynaFormulaire: valeursCombo, valeursListeSimple та valeursListeMultiple. Метод повертає ActionForward із ключем «afficherFormulaire».
  • контролер відображає перегляд /vues/formulaire.jsp, який був пов’язаний із ключем «afficherFormulaire» за допомогою тегу forward дії /init.

Дія /confirmation

      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • Дія /confirmation відбувається, коли користувач натискає кнопку [Envoyer] у вікні № 1. Після цього браузер «відправляє» контролеру Struts заповнену користувачем форму.
  • Об’єкт dynaFormulaire береться із сесії
  • викликається його метод reset. Після його виклику контролер Struts скопіює значення полів форми, надісланої клієнтом, у поля з такими самими іменами в об’єкті dynaFormulaire. Повернімося до списку полів цього об’єкта та розглянемо, як відбувається це копіювання:
Поле
Відповідний код HTML
Значення поля
після копіювання значень з форми
opt
<input type="radio" name="opt" value="oui">Так
<input type="radio" name="opt" value="no" checked="checked">Ні
- «так» або «ні» залежно від того, яка опція обрана
chk1
<input type="checkbox" name="chk1" value="on">
- «on», якщо встановлено прапорець chk1
- зберігає попереднє значення, якщо поле chk1 не відмічено
chk2
<input type="checkbox" name="chk2" value="on">
- «on», якщо поле chk2 було відмічено
- зберігає попереднє значення, якщо поле chk2 не відмічено
chk3
<input type="checkbox" name="chk2" value="on">
- «on», якщо поле chk3 було позначено
- зберігає попереднє значення, якщо поле chk3 не відмічено
champSaisie
<input type="text" name="champSaisie" value="">
- значення, введене користувачем у полі champSaisie
mdp
<input type="password" name="mdp" value="">
- значення, введене користувачем у полі mdp
boiteSaisie
<textarea name="boiteSaisie"></textarea>
- значення, введене користувачем у поле boiteSaisie
combo
<select name="combo">...</select>
- значення, вибране користувачем у combo
listeSimple
<select name="listeSimple" size="3">...</select>
- значення, вибране користувачем у listeSimple
listeMultiple
<select name="listeMultiple" multiple="multiple" size="5">
- масив рядків, що містить значення, вибрані користувачем у listeMultiple
secret
<input type="hidden" name="secret" value="xxx">
- «xxx».

Виникає проблема з полями, які не завжди отримують значення у запиті, надісланому браузером. Це стосується прапорців chk1–chk3 та двох списків listeSimple і listeMultiple. У цьому випадку ці поля зберігають своє попереднє значення, отримане під час попереднього циклу запит-відповідь.

Розглянемо, наприклад, прапорець chk1 і припустимо, що в попередньому циклі «запит-відповідь» користувач встановив цей прапорець. Тоді браузер надіслав у рядку параметрів свого запиту інформацію chk1="on". Отже, розробник присвоїв значення «on» полю chk1 у dynaFormulaire. Тепер припустимо, що в поточному циклі користувач не встановлює прапорець chk1. У цьому випадку в рядку параметрів нового запиту браузер не надсилає щось на кшталт chk1="off", а не надсилає нічого. Як наслідок, поле chk1 у dynaFormulaire збереже значення «on» і, отже, матиме значення, яке не відповідає тому, що вказано у формі, підтвердженій користувачем. Для вирішення цієї проблеми ми використаємо метод reset у dynaFormulaire. У цьому методі ми встановимо для трьох полів chk1, chk2, chk3 значення «off». У нашому прикладі з chk1, якщо користувач:

  • позначить прапорець chk1. У цьому випадку браузер надсилає інформацію chk1="on", і поле chk1 у dynaFormulaire перейде у стан «on»;
  • не встановлює прапорець chk1. Тоді браузер не надсилає значення для поля chk1, яке збереже своє попереднє значення «off». В обох випадках значення, записане в полі chk1 dynaFormulaire, є правильним.

Проблема є аналогічною для обох списків listeSimple та listeMultiple. Якщо в цих списках не було обрано жодного параметра, вони не будуть присутні в параметрах запиту і, отже, збережуть свої попередні значення. У методі reset об’єкта dynaFormulaire ми скинемо значення listeSimple, присвоївши йому порожній рядок, а listeMultiple — масив рядків довжиною 0.

  • Після виклику методу reset об’єкта dynaFormulaire контролер копіює в поля об’єкта dynaFormulaire інформацію, яка була надіслана йому у запиті клієнта
  • Створюється або повторно використовується об’єкт ForwardAction, і викликається його метод `execute`. ForwardAction — це попередньо визначений клас, який повертає об’єкт ActionForward, що вказує на представлення, визначене атрибутом «parameter» дії, у даному випадку /vues/confirmation.jsp.
  • Контролер відправляє цей вигляд. Цикл завершено.

Дія /affiche

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • Дія /affiche запускається при активації посилання [Retour vers le formulaire] у вікні № 2.
  • Тут немає форми, пов’язаної з цією дією. Тому ми одразу переходимо до виконання методу execute об’єкта ForwardAction, який поверне об’єкт ActionForward, що вказує на вигляд /vues/formulaire.jsp.

6.3.6. Файл повідомлень додатка

Третій розділ файлу struts-config.xml — це файл повідомлень:

        <message-resources 
          parameter="ApplicationResources"
            null="false"
      />    

Файл ApplicationResources.properties розміщується в папці WEB-INF/classes. Він буде порожнім. Навіть порожній, він все одно має бути вказаний у файлі конфігурації, інакше бібліотека тегів struts-bean, яку ми розглянемо трохи пізніше, видасть помилку. Ця бібліотека використовується у подачі confirmation.jsp.

6.4. Код подань

6.4.1. Вигляд formulaire.jsp

Нагадаємо, що цей вигляд відображається у двох випадках:

  • під час виклику дії /init у першому циклі «запит-відповідь»
  • під час виклику дії /affiche у наступних циклах

Код подання formulaire.jsp має такий вигляд:

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html>
  <head>
      <title>formulaire</title>
  </head>  
  <body background='<html:rewrite page="/images/standard.jpg"/>'>
      <h3>Formulaire Struts</h3>
    <hr>
    <html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
      <table border="0">
        <tr>
          <td>bouton radio</td>
          <td>
                        <html:radio name="dynaFormulaire" property="opt" value="oui">Oui</html:radio>
                        <html:radio name="dynaFormulaire" property="opt" value="non">Non</html:radio>                                            
          </td>
        </tr>
        <tr>
          <td>Cases à cocher</td>
          <td>
                        <html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
                        <html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
                        <html:checkbox name="dynaFormulaire" property="chk3">3</html:checkbox>                                                
          </td>
        </tr>
        <tr>
          <td>Champ de saisie</td>
          <td>
                        <html:text name="dynaFormulaire" property="champSaisie" />
          </td>
        </tr>
        <tr>
          <td>Mot de passe</td>
          <td>
              <html:password name="dynaFormulaire" property="mdp" />
          </td>
        </tr>
        <tr>
          <td>Boîte de saisie multilignes</td>
          <td>
              <html:textarea name="dynaFormulaire" property="boiteSaisie" />
          </td>
        </tr>
        <tr>
          <td>Combo</td>
          <td>
              <html:select name="dynaFormulaire" property="combo">
                            <html:options name="dynaFormulaire" property="valeursCombo"/>
                        </html:select>
          </td>
        </tr>
        <tr>
          <td>
                        <table>
                            <tr>
                                <td>Liste à sélection unique</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>
                                </td>
                            </tr>
                        </table>
          <td>
              <html:select name="dynaFormulaire" property="listeSimple" size="3">
                            <html:options name="dynaFormulaire" property="valeursListeSimple"/>                        
                        </html:select>
          </td>
        </tr>
        <tr>
                    <td>
                        <table>
                            <tr>
                                <td>Liste à sélection multiple</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>                                
                                </td>
                            </tr>
                        </table>
                    </td>
          <td>
              <html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
                            <html:options name="dynaFormulaire" property="valeursListeMultiple"/>                        
                        </html:select>
          </td>
        </tr>
      </table>
      <html:hidden name="dynaFormulaire" property="secret"/>
            <br>
            <hr>
            <html:submit>Envoyer</html:submit> 
    </html:form>
  </body>
</html>

Ця сторінка JSP використовує теги з бібліотеки struts-html. Нагадаємо, що для використання бібліотеки тегів необхідно:

  • задекларувати її у файлі web.xml додатка за допомогою тегу <tag-lib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  • розмістіть код цієї бібліотеки десь у дереві каталогів додатка, тут WEB-INF/struts-html.tld
  • оголосіть використання цієї бібліотеки на початку сторінок JSP, які її використовують:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

Вигляд formulaire.jsp використовує теги, які ми зараз пояснимо:

balise
<body background="<html:rewrite page="/images/standard.jpg"/>">
traduction HTML
<body background="/formulaire2/images/standard.jpg">
explication
тег html:rewrite дозволяє обійти ім'я додатка в URL. Він має один атрибут:
page
URL — потрібно переписати
Отже, як показано вище, якщо вирішити назвати додаток «formulaire3», код атрибута background не потрібно переписувати. Тег html:rewrite згенерує новий код HTML
background="/formulaire3/images/standard.jpg"
balise
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
traduction HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
explication
Тег html:form дозволяє створити тег HTML form. Він має кілька атрибутів:
action
action Struts, куди має бути відправлена форма — має відповідати одній із дій, визначених у struts-config.xml
name
опціональний — ім’я біна ActionForm або його похідного, в який мають бути записані або з якого мають бути зчитані значення надісланої форми. За відсутності цього атрибута використовується форма, пов’язана з дією, визначеною атрибутом action. Ця інформація міститься у файлі конфігурації (атрибут name дії).
type
необов’язковий — клас Java, який слід інстанціювати для форми. За відсутності цього атрибута використовується клас, пов’язаний з дією, визначеною атрибутом action. Ця інформація міститься у файлі конфігурації (атрибут type дії).
Бачимо, що за замовчуванням згенерований код HTML використовує метод POST. У цьому ж коді HTML код дії URL було переписано таким чином, щоб перед ним стояв префікс із назвою додатка, а наприкінці — суфікс .do.
balise
<html:radio name="dynaFormulaire" property="opt" value="так">Так</html:radio>
traduction HTML
<input type="radio" name="opt" value="oui">
explication
тег html:radio використовується для генерації тегу HTML <input type="radio" ...>. Він підтримує різні атрибути:
name
опціональний — ім’я bean ActionForm або похідного, в який має бути розміщено або з якого має бути зчитано значення поля. За відсутності цього атрибута використовується форма, пов’язана з тегом <html:form>.
property
ім’я поля біна форми, пов’язаного з перемикачем, для читання та запису.
value
необов’язкове — значення, яке слід присвоїти полю HTML
Текст між тегами початку та кінця — це текст, який буде відображатися поруч із перемикачем.
balise
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
traduction HTML
<input type="checkbox" name="chk1" value="on">
explication
тег html:checkbox використовується для генерації тегу HTML <input type="checkbox" ...>. Він підтримує різні атрибути:
name
опціональний — ім’я bean ActionForm або похідного, в який має бути записано або з якого має бути зчитано значення поля. За відсутності цього атрибута використовується форма, пов’язана з тегом <html:form>.
property
ім’я поля біна форми, пов’язаного з прапорцем, для читання та запису.
value
необов’язкове — значення, яке слід присвоїти полю HTML
Текст між тегами початку та кінця — це текст, який буде відображатися поруч із прапорцем.
balise
<html:text name="dynaFormulaire" property="champSaisie" />
traduction HTML
<input type="text" name="champSaisie" value="">
explication
тег html:text використовується для генерації тегу HTML <input type="text" ...>. Він підтримує різні атрибути:
name
опціональний — ім’я bean ActionForm або похідного, в який має бути розміщено або з якого має бути зчитано значення поля. За відсутності цього атрибута використовується форма, пов’язана з тегом <html:form>.
property
ім’я поля біна форми, пов’язаного з полем введення даних для читання та запису.
value
необов’язкове — значення, яке слід вказати в полі HTML
balise
<html:password name="dynaFormulaire" property="mdp" />
traduction HTML
<input type="password" name="mdp" value="">
explication
тег html:password використовується для генерації тегу HTML <input type="password" ...>. Він підтримує різні атрибути:
balise
<html:textarea name="dynaFormulaire" property="boiteSaisie" />
traduction HTML
<textarea name="boiteSaisie"></textarea>
explication
Тег html:textarea використовується для генерації тегу HTML <textarea>...</textarea>. Він підтримує різні атрибути:
name
опціональний — ім’я bean-а ActionForm або похідного, в який має бути розміщено або з якого має бути зчитано значення поля. За відсутності цього атрибута використовується форма, пов’язана з тегом <html:form>.
property
ім’я поля біна форми, пов’язаного з полем пароля для читання та запису.
value
необов’язкове — значення, яке слід присвоїти полю HTML
balise
<html:select name="dynaFormulaire" property="combo">....</html:select>
traduction HTML
<select name="combo">...</select>
explication
тег html:select використовується для генерації тегу HTML <select>...</select>. Він підтримує різні атрибути:
name
опціональний — ім’я bean ActionForm або похідного, в який має бути розміщено або з якого має бути зчитано значення поля. За відсутності цього атрибута використовується форма, пов’язана з тегом <html:form>.
property
ім’я поля біна форми, пов’язаного з полем введення даних для читання та запису.
value
необов’язкове — значення, яке слід присвоїти полю HTML. Буде обрано варіант комбінованого списку з цим значенням.
balise
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="valeursCombo"/>
</html:select>
traduction HTML
<option value="combo1">combo1</option>
<option value="combo2">combo2</option>

explication
Тег html:options використовується для генерації тегів HTML <option>...</option> всередині тегу HTML <select>. Існують різні способи вказати, як знайти значення для заповнення списку вибору. Тут ми використали атрибути name та property:
name
необов’язковий — ім’я bean-а ActionForm або похідного, в який має бути записано або з якого має бути зчитано значення поля. За відсутності цього атрибута використовується форма, пов’язана з тегом <html:form>.
property
ім’я поля bean-форми, що містить значення списку. Це має бути масив символьних рядків.

Два інші списки генеруються аналогічно до попереднього:

          <html:select name="dynaFormulaire" property="listeSimple" size="3">
            <html:options name="dynaFormulaire" property="valeursListeSimple"/>            
        </html:select>

У наведеному вище прикладі вказано атрибут size, значення якого відрізняється від 1, щоб отримати список замість комбінованого списку.

<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
        <html:options name="dynaFormulaire" property="valeursListeMultiple"/>                
    </html:select>

Вище вказано атрибут multiple="true", щоб отримати список із можливістю множинного вибору.

balise
<html:hidden name="dynaFormulaire" property="secret"/>
traduction HTML
<input type="hidden" name="secret" value="xxx">
explication
тег html:hidden використовується для генерації тегу HTML <input type="hidden" ...>.
name
необов’язковий — назва bean-а ActionForm або його похідного, в який має бути записано або з якого має бути зчитано значення поля. За відсутності цього атрибута використовується форма, пов’язана з тегом <html:form>.
property
ім'я поля біна форми, пов'язаного з прихованим полем. Значення «xxx», присвоєне полю HTML secret, походить із визначення форми у файлі конфігурації. Там для поля secret було визначено початкове значення «xxx».

Щоб добре зрозуміти зв’язок між представленням formulaire.jsp та біном dynaFormulaire, який представляє його в пам’яті, слід пам’ятати, що бін dynaFormulaire використовується як для читання, так і для запису:

Запит надсилається, коли користувач натискає кнопку [Envoyer] у формі. Після цього браузер «відправляє» форму HTML на дію /confirmation. Ми вже пояснювали, що відбувається в цей момент, зокрема те, що поля dynaFormulaire отримають значення полів з такими самими іменами з форми HTML.

Що відбувається, коли контролер запитує відображення подання formulaire.jsp у відповідь на запит? Розглянемо теги по черзі:

balise
<body background="<html:rewrite page="/images/standard.jpg"/>">
fonction
генерує код HTML
<body background="/formulaire2/images/standard.jpg">
balise
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
</html:form>
fonction
генерує код HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
balise
<html:radio name="dynaFormulaire" property="opt" value="так">Так</html:radio>
<html:radio name="dynaFormulaire" property="opt" value="no">Ні</html:radio>
fonction
Якщо значення поля opt у dynaFormulaire дорівнює «так», генерується код HTML
<input type="radio" name="opt" value="oui" checked="checked">Oui
<input type="radio" name="opt" value="non">Non
balise
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk3">3</html:checkbox>
fonction
Якщо поля chk1 і chk3 у dynaFormulaire мають значення «on», а поле chk2 — «off», згенеруйте код HTML
<input type="checkbox" name="chk1" value="on" checked="checked">1
<input type="checkbox" name="chk2" value="on">2
<input type="checkbox" name="chk3" value="on" checked="checked">3                                                
balise
<html:text name="dynaFormulaire" property="champSaisie" />
fonction
якщо значення поля champSaisie дорівнює «це тест», генерується код HTML
<input type="text" name="champSaisie" value="ceci est un essai">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
якщо значення поля mdp дорівнює "azerty", генерує код HTML
<input type="password" name="mdp" value="azerty">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
якщо значення поля mdp дорівнює «azerty», генерує код HTML
<input type="password" name="mdp" value="azerty">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
якщо значення поля mdp дорівнює "azerty", генерує код HTML
<input type="password" name="mdp" value="azerty">
balise
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="valeursCombo"/>
</html:select>
fonction
якщо значення поля комбінованого списку дорівнює «combo2», генерує код HTML
<select name="combo">
    <option value="combo0">combo0</option>
    <option value="combo1">combo1</option>
    <option value="combo2" selected="selected">combo2</option>
    <option value="combo3">combo3</option>
    <option value="combo4">combo4</option>
</select>
balise
<html:select name="dynaFormulaire" property="listeSimple" size="3">
<html:options name="dynaFormulaire" property="valeursListeSimple"/>
</html:select>
fonction
якщо значення поля listeSimple дорівнює «simple1», генерується код HTML
<select name="listeSimple" size="3">
    <option value="simple0">simple0</option>
    <option value="simple1" selected="selected">simple1</option>
    <option value="simple2">simple2</option>
...
</select>
balise
<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
<html:options name="dynaFormulaire" property="valeursListeMultiple"/>
</html:select>
fonction
якщо поле listeMultiple є масивом {"multiple0","multiple2"}, генерує код HTML
<select name="listeMultiple" multiple="multiple" size="5">
    <option value="multiple0" selected="selected">multiple0</option>
    <option value="multiple1">multiple1</option>
    <option value="multiple2" selected="selected">multiple2</option>
    <option value="multiple3">multiple3</option>
...
</select>
balise
<html:hidden name="dynaFormulaire" property="secret"/>
fonction
якщо поле secret має значення "xxx", генерує код HTML
<input type="hidden" name="secret" value="xxx">
balise
<html:submit>Надіслати</html:submit>
fonction
генерує код HTML
<input type="submit" value="Envoyer">

Останнє, що слід пояснити, — це код JavaScript, включений на сторінку JSP і пов’язаний із двома кнопками [Effacer], які скасовують вибір елементів, виділених у списках listeSimple та listeMultiple:

<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>                                
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>

Тег

<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">

генерує такий код HTML:

<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">

Щоб зрозуміти код JavaScript, пов’язаний із кнопками [Effacer], нагадаємо, як позначаються різні елементи веб-документа в коді JavaScript, що використовує цей документ:

Дані
Значення
document
позначає весь веб-документ
document.forms
позначає сукупність форм, визначених у документі
document.forms[i]
позначає форму № i у документі
document.forms["nomFormulaire"]
позначає формуляр <form>, атрибут name якого дорівнює "nomFormulaire"
document.nomFormulaire
позначає форму <form>, атрибут name якої дорівнює "nomFormulaire"
document.[formulaire].elements
позначає сукупність елементів, що входять до форми, позначеної виразом [formulaire]. Ця сукупність включає всі теги <input>, <textarea>, <select> зазначеної форми.
document.[formulaire].elements[i]
позначає елемент № i з [formulaire]
document.[formulaire].elements["nomComposant"]
позначає елемент [formulaire], у якого атрибут name дорівнює nomComposant
document.[formulaire]. nomComposant
позначає елемент [formulaire], у якого атрибут name дорівнює nomComposant
document.[formulaire].[composant].value
позначає значення компонента [composant] форми [formulaire], коли код HTML цієї форми може мати атрибут value (<input>, <textarea>)
document.[formulaire].[select].selectedIndex
позначає індекс опції, обраної у списку. Використовується для читання та запису. Встановлення цього властивості на -1 скасовує вибір усіх елементів списку.
document.[formulaire].[select].options
позначає масив опцій, пов’язаних із тегом <select>
document.[formulaire].[select].options[i]
позначає опцію № i вказаного тегу <select>
document.[formulaire].[select].options[i].selected
булеве значення, що вказує, чи обрано (true) опцію № i вказаного тегу [select]. Може використовуватися як для читання, так і для запису

Повернемося до JavaScript-коду двох кнопок:

<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>                                
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>

При натисканні на кнопку виконується код, пов'язаний з атрибутом «onclick». У цьому випадку це вбудований код. Найчастіше пишуть onclick="функція(...)", де функція — це функція, визначена в тезі <script language="javascript">...</script>. Що робить наведений вище код? Прокоментуємо код першої кнопки:

this
позначає веб-документ, у якому знаходиться кнопка
this.form
позначає форму, у якій знаходиться кнопка
this.form.listeSimple
позначає компонент listeSimple форми
this.form.listeSimple.selectedIndex
позначає індекс опції, вибраної в listeSimple. Встановлення цього параметра на -1 призводить до скасування вибору всіх опцій.

6.4.2. Вигляд confirmation.jsp

Нагадаємо, що цей вигляд відображається після виконання дії /confirmation, c.a.d, після того, як форма, що міститься у вигляді formulaire.jsp, була відправлена веб-клієнтом. Його єдиною метою є відображення значень, введених користувачем. Його код такий:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
    <head>
      <title>Confirmation</title>
  </head>
  <body background="<html:rewrite page="/images/standard.jpg"/>">
      <h3>Confirmation des valeurs saisies</h3>
    <hr/>
    <table border="1">
        <tr>
        <td>Bouton radio</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="opt"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk1</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk1"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk2</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk2"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk3</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk3"/></td>
      </tr>

        <tr>
        <td>Champ de saisie</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="champSaisie"/></td>
      </tr>
        <tr>
        <td>Mot de passe</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="mdp"/></td>
      </tr>

        <tr>
        <td>Boîte de saisie</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="boiteSaisie"/></td>
      </tr>

        <tr>
        <td>combo</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="combo"/></td>
      </tr>
        <tr>
        <td>liste simple</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="listeSimple"/></td>
      </tr>
            <logic:iterate id="choix" indexId="index" name="dynaFormulaire" property="listeMultiple">
          <tr>
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
        </tr>
            </logic:iterate>
    </table>
        <br>
    <html:link page="/affiche.do">
            Retour au formulaire
        </html:link>    
  </body>
</html>

Тут ми вводимо дві нові бібліотеки тегів: struts-bean та struts-logic. Бібліотека struts-bean дозволяє отримати доступ до об’єктів, розміщених у запиті, сесії або контексті додатка. Бібліотека struts-logic дає змогу впроваджувати логіку виконання за допомогою тегів. Ці дві бібліотеки аж ніяк не є обов’язковими. Як ми вже бачили, сторінка JSP може:

  • отримувати об’єкти із запиту (request.getAttribute(...)), сесії (session.getAttribute(...)) або контексту додатка
  • включати динамічні елементи в код HTML за допомогою змінних <%= змінна %>
  • містити код Java <% код Java %>

Включення коду Java у сторінки JSP заважає всім, хто прагне суворого розділення між логікою додатка (кодом Java) та представленням (використанням тегів). Тому для них були створені бібліотеки тегів.

Ми будемо діяти так само, як і для подання formulaire.jsp, і пояснимо кожну з тегів, присутніх у коді confirmation.jsp, якщо вони ще не зустрічалися у поданні formulaire.jsp. Насамперед зауважимо, що сторінка починається з оголошення трьох бібліотек тегів, які вона використовуватиме:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

Нагадаємо також, що ці три бібліотеки мають бути оголошені у файлі web.xml додатка. Тепер прокоментуємо теги документа formulaire.jsp:

balise
<bean:write name="dynaFormulaire" scope="session" property="opt"/>
fonction
записує значення в поточний потік HTML. Тег bean:write підтримує такі атрибути:
name: ім’я об’єкта, який потрібно використати
scope: область дії (request, session, context), в якій слід шукати цей об’єкт
property: поле об’єкта, позначеного атрибутом name, властивість якого потрібно записати. Це поле може бути об’єктом будь-якого типу. Використовуватиметься метод toString цього об’єкта.
Тут записується значення поля opt об’єкта dynaFormulaire. Буде «так», якщо користувач встановив прапорець з атрибутом value="так", або «ні», якщо він встановив прапорець з атрибутом value="ні"
balise
<bean:write name="dynaFormulaire" scope="session" property="chk1"/>
fonction
записує значення поля chk1 з dynaFormulaire. Буде або «on», якщо користувач встановив прапорець, або «off» в іншому випадку. Те саме стосується полів chk2 та chk3.
balise
<bean:write name="dynaFormulaire" scope="session" property="champSaisie"/>
fonction
записує значення поля champSaisie з dynaFormulaire, тобто текст, введений користувачем у це поле. Те саме стосується mdp, boiteSaisie.
balise
<bean:write name="dynaFormulaire" scope="session" property="combo"/>
fonction
записує значення поля комбінованого списку dynaFormulaire. Ми отримаємо атрибут value елемента <option>, вибраного користувачем.
balise
<bean:write name="dynaFormulaire" scope="session" property="listeSimple"/>
fonction
записує значення поля listeSimple з dynaFormulaire. Якщо користувач вибрав елемент <option>, то буде використано його атрибут value. В іншому випадку буде використано порожній рядок.
balise
            <logic:iterate id="choix" indexId="index" name="dynaFormulaire" property="listeMultiple">
          <tr>
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
        </tr>
            </logic:iterate>
fonction
Тут ми вводимо логічні теги. Ми маємо справу зі списком з кількома варіантами вибору. Значенням поля listeMultiple об’єкта dynaFormulaire є масив рядків. У Java ми б написали цикл. Тег logic:iterate дозволяє нам виконати цей самий цикл без написання коду на Java. У наведеному прикладі тег logic:iterate має такі атрибути:
name="dynaFormulaire": ім’я об’єкта, який потрібно використовувати
property="listeMultiple": ім’я властивості, яка в об’єкті, вказаному в атрибуті name, містить колекцію, що буде обходитися в циклі. У даному випадку ця колекція — це масив значень, вибраних у listeMultiple. Цей масив може бути порожнім.
id="choix": ідентифікатор, що позначає поточний елемент масиву на кожному циклі. Під час першої ітерації «choix» буде дорівнювати listeMultiple[0], під час другої — listeMultiple[1] і так далі.
indexID="index": ідентифікатор, що позначає індекс поточного елемента масиву під час кожного проходу циклу. Під час першої ітерації index матиме значення 0, під час другої — 1 і так далі.
Код HTML, що міститься між тегами <logic:iterate ...> та </logic:iterate>, повторюється для кожного елемента колекції, позначеної парою (name,property). Динамічна частина цього коду виглядає так:
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
З огляду на вищесказане, під час ітерації № i (i>=0) згенерований код HTML еквівалентний такому коду:
          <td>liste multiple[<%=i%>]</td>
          <td><%=listeMultiple[i]%></td>
balise
    <html:link page="/affiche.do">
            Retour au formulaire
        </html:link>    
fonction
генерує посилання, пов'язане з контекстом додатка, що дозволяє обійтися без знання цього контексту. Код HTML, згенерований цим тегом, виглядає так:
<a href="/formulaire2/affiche.do">Retour au formulaire</a>

6.5. Класи Java

Файл конфігурації struts-config.xml посилається на два класи Java:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >

Клас DynaFormulaire — це клас, який міститиме значення подання № 1 formulaire.jsp. Клас InitFormulaireAction — це клас, який оброблятиме значення форми, надісланої за допомогою кнопки [Envoyer] з formulaire.jsp.

6.5.1. Клас DynaFormulaire

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

  • поле для позначки, яке користувач не позначив
  • список, що містить більше ніж 1 елемент, або жоден варіант не було обрано

Для форм, що містять цей тип компонента, метод reset повинен

  • присвоювати значення «off» полю, пов’язаному з прапорцем
  • присвоїти порожній рядок полю, пов’язаному зі списком з одним варіантом вибору
  • присвоїти масив символьних рядків нульового розміру полю, пов’язаному зі списком з можливістю множинного вибору

Таким чином, якщо ці поля не отримують значення із запиту, вони зберігають значення, присвоєне методом reset, яке відповідає стану компонента у формі, затвердженій користувачем (поле не відмічене, список без жодного вибраного елемента).

Код класу DynaFormulaire, похідного від класу DynaActionForm, є таким:

package istia.st.struts.formulaire;

import org.apache.struts.action.DynaActionForm;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;

public class DynaFormulaire extends DynaActionForm {
  public void reset(ActionMapping mapping, HttpServletRequest request){
    // скидання прапорців — значення «off»
    set("chk1","off");
    set("chk2","off");
    set("chk2","off");
    // скидання listeSimple — порожній рядок
    set("listeSimple","");
     // скидання listeMultiple — порожній масив
    set("listeMultiple",new String[]{});
  }
}

6.5.2. Клас InitFormulaireAction

Клас InitFormulaireAction у файлі struts-config.xml пов'язаний з дією /init:

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

Дія /init використовується лише один раз під час початкового створення об’єкта DynaFormulaire. Її метою є заповнення вмісту трьох списків комбінованого поля: listeSimple, listeMultiple. Цей вміст надається у вигляді трьох масивів, які є властивостями об’єкта dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
...
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                                          
        </form-bean>            

Після того як масиви valeursCombo, valeursListeSimple, valeursListeMultiple будуть ініціалізовані за допомогою InitFormulaireAction, їх більше не потрібно буде ініціалізувати. Адже об’єкт dynaFormulaire розміщується в сесії і, отже, зберігає своє значення протягом циклів «запит-відповідь». Саме тому дія /init виконується лише один раз. Код InitFormulaireAction виглядає так:

package istia.st.struts.formulaire;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;

public class InitFormulaireAction
  extends Action {
  public ActionForward execute(ActionMapping mapping, ActionForm form,
       HttpServletRequest request, HttpServletResponse response) throws IOException,    ServletException {

     // підготовка форми до відображення

     // необхідну інформацію про форму заносимо в її bean
    DynaFormulaire formulaire = (DynaFormulaire) form;
    formulaire.set("valeursCombo", getValeurs(5, "combo"));
    formulaire.set("valeursListeSimple", getValeurs(7, "simple"));
    formulaire.set("valeursListeMultiple", getValeurs(10, "multiple"));
     // повертаємо контроль
    return mapping.findForward("afficherFormulaire");
  } //виконується

   // список значень комбінованого списку
  private String[] getValeurs(int taille, String label) {
    String[] valeurs = new String[taille];
    for (int i = 0; i < taille; i++) {
      valeurs[i] = label + i;
    }
    return valeurs;
  }
}
  • Клас є похідним від класу Action. Це обов'язково.
  • Контролер Struts використовує об’єкт Action через його метод execute. Отже, саме цей метод потрібно перевизначити. Цей метод приймає такі параметри:
    • ActionMapping mapping: об’єкт, що представляє конфігурацію додатка в struts-config.xml
    • ActionForm form: форма, пов’язана з дією, якщо така визначена в конфігурації дії (атрибут name дії).
    • HttpServletRequest request: запит клієнта
    • HttpServletResponse: відповідь клієнту
  • клас InitFormulaireAction повинен ініціалізувати форму dynaFormulaire. Вона передається до методу execute у вигляді параметра ActionForm form. Нагадаємо, що dynaFormulaire належить до типу DynaFormulaire — класу, похідного від класу DynaActionForm, який, у свою чергу, є похідним від класу ActionForm.
  • У методі `execute` значенням присвоюються три поля valeursCombo, valeursListeSimple, valeursListeMultiple за допомогою методу `set` класу DynaActionForm. Для простоти ці значення є довільними масивами. Зауважимо, що метод set присвоює значення існуючому полю. Він не може використовуватися для створення нових полів. Тому необхідно визначити три поля valeursCombo, valeursListeSimple, valeursListeMultiple у визначенні об’єкта dynaFormulaire у struts-config.xml.
  • Метод `execute` завершується, повертаючи контролеру ключ подання, яке слід відобразити у відповіді клієнту. У даному випадку це ключ afficherFormulaire, який у файлі struts-config.xml було пов’язано з поданням /vues/formulaire.jsp.

6.6. Розгортання

Структура додатка виглядає наступним чином:

  

Image

Image

Нагадаємо, що наведений вище файл ApplicationResources.properties необхідний для бібліотеки тегів struts-bean. Відомо, що цей файл містить повідомлення додатка. До них має доступ бібліотека struts-bean. У даному випадку наш додаток не визначає жодного повідомлення. Тому файл ApplicationResources.properties існує, але є порожнім.

6.7. Висновок

У цьому уроці ми детально розглянули, як працювати з різними компонентами форми HTML. Тепер ми можемо використовувати складні форми у наших додатках Struts.