9. Приклад 07 — Теги форми
Ми створимо та використаємо таку форму:
![]() | ![]() |
Ми розширимо поняття введення параметрів, розглянуте для поля введення тексту, на інші HTML-елементи форми.
9.1. Проєкт NetBeans
![]() |
- у [1], представлення проекту [Formx.JSP]
- у [2], файл конфігурації Struts та інтернаціоналізовані повідомлення
- у [3], дії — у [Formx.java] та ще один файл конфігурації Struts.
9.2. Налаштування Struts
Файл [struts.xml] має такий вигляд:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.custom.i18n.resources" value="messages" />
<include file="example/example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Form</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
</struts>
- рядок 9: включає інший файл конфігурації [example.xml]. Саме він буде налаштовувати дії.
- рядки 11–19: пакет default. Визначає адресу перенаправлення для URL /. Вона буде перенаправлена на URL /example/Form.action.
Файл [example.xml], що налаштовує дії, має такий вигляд:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.JSP</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.JSP</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.JSP</result>
</action>
</package>
</struts>
- рядки 7–17: визначають дії /example/Form, /example/Form1, /example/Form2, де /example — це простір імен (рядок 7), а Formx — дії.
- рядки 8–10: виконання дії Form призведе до відображення подання /example/Form.JSP.
- рядки 11–13: виконання дії Form1 призведе до відображення подання /example/Form1.JSP.
- рядки 14–16: виконання дії Form2 призведе до відображення подання /example/Form2.JSP.
9.3. Файли повідомлень
Ми не будемо зупинятися на інтернаціоналізації проекту. Ми вже розглядали це в прикладі 01. Наводимо вміст файлу [messages.properties], щоб читач міг зрозуміти наступні види.
Form.francais=Fran\u00E7ais
Form.anglais=Anglais
Form.titre=Struts 2 - les tags de formulaire
Form.message=Struts 2 - les tags de formulaire
Form.langues=langues
Form.textfield=1-textfield
Form.password=2-password
Form.textarea=3-textarea
Form.select1=4-select (multiple=false, size=1)
Form.select1.header=<-- select1 -->
Form.select2=5-select (multiple=false, size=3)
Form.select3=6-select (multiple=true, size=3)
Form.radio=7-radio
Form.checkbox=8-checkbox
Form.checkboxlist=9-checkboxlist
Form.hidden=10-hidden
Form.submitText=Valider
Form.buttonRazText=Raz
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.textfield=1-textfield
Confirmation.password=2-password
Confirmation.textarea=3-textarea
Confirmation.select1=4-select (multiple=false, size=1)
Confirmation.select2=5-select (multiple=false, size=3)
Confirmation.select3=6-select (multiple=true, size=3)
Confirmation.radio=7-radio
Confirmation.checkbox=8-checkbox
Confirmation.checkboxlist=9-checkboxlist
Confirmation.hidden=10-hidden
9.4. Вигляд [Form.JSP] — частина введення
Його зовнішній вигляд такий:
![]() |
Вона виглядає так:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="textfield" key="Form.textfield" />
<s:password name="password" key="Form.password"/>
<s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
<s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
<s:radio name="radio" list="radioValues" key="Form.radio"/>
<s:checkbox name="checkbox" key="Form.checkbox"/>
<s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="submitText"/>
</s:form>
<hr/>
...
</body>
</html>
- Форма починається з 26-го рядка і закінчується 38-м рядком. У 26-му рядку відсутній атрибут action. Цей атрибут вказує, до якої дії будуть відправлені дані форми. За відсутності атрибута action дані будуть відправлені до дії, яка призвела до відображення цього виду, у даному випадку — до дії [Form].
- рядок 27: поле введення. Атрибут key визначає його назву. Атрибут name — це ім’я параметра, який буде передано. Рядок, що передається для цього поля, матиме такий вигляд:
Назва параметра відповідає полю дії [Form]. Значення поля введення texte_saisi буде вставлено в поле textfield дії [Form]. І навпаки, якщо вікно [Form.JSP] відображається в результаті дії [Form], значення поля введення буде відповідати значенню поля textfield дії [Form]. Отже, це поле використовується як для читання, так і для запису. Для цього клас [Form] повинен мати методи getTextField та setTextField.
Цей висновок справедливий для всіх наступних тегів введення даних. Ми не будемо його повторювати.
- рядок 28: введення пароля. Рядок, що надсилається до дії [Form], матиме вигляд
У дії [Form] має існувати поле password з відповідними методами get та set.
- рядок 29: введення багаторядкового тексту в поле розміром 5 рядків і 40 стовпців. Рядок, що надсилається до дії [Form], матиме вигляд
У дії [Form] має бути поле textarea з відповідними методами get та set.
- рядок 30: випадаючий список (size=1) з можливістю вибору одного елемента. Можна вибрати лише одне значення зі списку. Рядок, що надсилається до дії [Form], матиме такий вигляд:
У дії [Form] має бути присутнє поле select1 з відповідними методами get / set.
Атрибут key — це назва списку. Атрибут list визначає список значень, які потрібно помістити в комбінований список. Тут для заповнення комбінованого списку буде викликано метод getSelect1Values дії [Form]. Цей метод може повертати колекцію, словник або масив. У цьому випадку він поверне масив рядків [chaine1, chaine2, ...], який згенерує такий HTML-код:
<option value="chaine1">chaine1</option>
<option value="chaine2">chaine2</option>
...
Текст між тегами <option>...</option> відобразиться у комбінованому списку. Атрибут value визначає значення, яке слід відправити, якщо користувач вибере цю опцію. У цьому випадку атрибут value та текст, що відображається у комбінованому списку, є однаковими. Найчастіше це не так. Якщо вибрано другий варіант, до дії [Form] буде відправлено такий рядок:
Тоді поле [Form].select1 отримає значення chaine2. І навпаки, якщо під час відображення форми це поле має значення chaine3, то візуально третій елемент
<option value="chaine3">chaine3</option>
буде відображатися як вибраний у комбінованому списку.
Атрибут headerValue визначає текст, який має відображатися як перший варіант списку, а headerKey — значення, яке має бути відправлене, якщо користувач обере цей варіант.
- рядок 31: тут знову список розміром 3 (size=3): на відміну від попереднього списку, де видно лише один елемент, тут будуть видні 3 елементи списку. Режим вибору залишається тим самим. Можна вибрати лише один елемент.
- рядок 32: знову список, але з можливістю множинного вибору (multiple=true). У цьому випадку значення, що передається до дії [Form], матиме такий вигляд:
якщо було вибрано параметри chaine2 та chaine5. Коли для одного й того самого параметра, у даному випадку select3, заноситься кілька значень, дія повинна мати поле з назвою параметра та бути типу tableau. Так, наприклад, у даному випадку дія [Form] може мати поле такого вигляду:
та відповідні методи get / set. Масив select3 отримає масив рядків [chaine2,chaine5]. І навпаки, під час відображення подання [Form.JSP] значення поля [Form].select3 визначають, які опції зі списку select3 будуть позначені як вибрані. Тут також використовується режим читання/запису.
- рядок 33: група перемикачів. Назва групи задається атрибутом key. Назви окремих перемикачів задаються атрибутом list. Значенням цього атрибута є назва методу дії [Form], який повинен повертати колекцію, словник або масив. У цьому випадку метод [Form].getRadioValues поверне масив рядків [chaine1,chaine2,...], який згенерує такі HTML-теги:
<input type="radio" name="radio" ... value="chaine1"/>chaine1
<input type="radio" name="radio" ... value="chaine2"/>chaine2
...
Якщо встановлено перемикач chaine2, відправлене значення буде
, і це значення буде вставлено в поле [Form].radio.
- рядок 34: прапорець. Якщо він встановлений, до дії буде передано такий рядок параметрів: [Form]
Якщо його не позначено, ланцюжок параметрів не надсилається. Struts 2 має внутрішній механізм, завдяки якому все відбувається так, ніби ланцюжок
був відправлений.
- рядок 35: список прапорців. Можна встановити кілька прапорців. Назва групи задається атрибутом key. Назви окремих прапорців задаються атрибутом list. Значенням цього атрибута є ім’я методу дії [Form], який повинен повертати колекцію, словник або масив. У цьому випадку метод [Form].getCheckboxlistValues поверне масив рядків [chaine1,chaine2,...], який згенерує такі HTML-теги:
<input type="checkbox" name="checkboxlist" ... value="chaine1"/>chaine1
<input type="checkbox" name="checkboxlist" ... value="chaine2"/>chaine2
...
Якщо користувач позначить поля з назвами chaine2 та chaine5, наступний рядок символів буде відправлений до дії [Form]:
Таблиця [chaine2, chaine5] буде прив’язана до поля [Form].checkboxlist, яке, отже, має бути типу «масив символьних рядків», як і у випадку списків із можливістю множинного вибору. І навпаки, під час відображення подання [Form.JSP] значення поля [Form].checkboxlist визначають, які прапорці будуть встановлені.
- рядок 36: приховане поле. Приховане поле — це поле, яке надсилається без введення даних користувачем. Його значення встановлюється програмістом. У цьому випадку приховане поле отримає значення з поля [Form].hidden. Це саме значення буде надіслано у вигляді:
і перепризначено полю [Form].hidden.
- рядок 37: кнопка типу submit. Натискання на цю кнопку відправить усі значення форми до дії [Form]. Рядок відправлених параметрів матиме такий вигляд:
textfield=texte&password=&textarea=ligne1%0D%0Aligne2%0D%0A&select1=z%C3%A9ro&select2=trois&select3=z%C3%A9ro&select3=deux&__multiselect_select3=&radio=bleu&checkbox=true&__checkbox_checkbox=true&checkboxlist=v%C3%A9lo&checkboxlist=bus&__multiselect_checkboxlist=&hidden=initial&submitText=Valider
9.5. Акція [Form] — частина введення даних
Її код такий:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form extends ActionSupport {
// конструктор без параметрів
public Form() {
}
// поля форми
private String textfield = "texte";
private String password = "secret";
private String textarea = "ligne1\nligne2\n";
private String select1 = "zéro";
private String[] select1Values = new String[]{"zéro", "un", "deux"};
private String select2 = "trois";
private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String radio = "bleu";
private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
private Boolean checkbox = false;
private String[] checkboxlist = new String[]{"vélo", "bus"};
private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
private String hidden = "initial";
private String submitText;
// значення, вибрані в полі select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// значення, вибрані в полі checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// допоміжний метод
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// методи getter та setter для полів
....
}
- рядок 1: поле, пов’язане з тегом textfield у формі. Використовується як для ініціалізації цього поля введення, так і для отримання його значення. Під час виконання дії POST отримує значення, введене в це поле.
- рядок 2: поле, пов’язане з тегом password у формі. Під час виконання POST отримує значення, введене в це поле.
- рядок 13: пов’язаний із тегом textarea форми. Під час виконання POST отримує текст, введений у це поле.
- рядок 14: пов'язаний з тегом select1 форми, список з одним варіантом вибору. Його початкове значення вибирає елемент зі списку. Буде вибрано той елемент, у якого атрибут value дорівнює цьому значенню. Під час виконання POST отримує атрибут value від опції, обраної у комбінованому списку.
- рядок 15: символьні рядки, які будуть заповнювати комбінований список select1.
- рядки 16 і 17: те саме, що й select1
- рядок 18: пов'язаний з тегом select1 форми, список з можливістю вибору декількох елементів. Початкові значення в таблиці вибирають відповідні елементи зі списку. Будуть вибрані ті елементи, у яких атрибут value дорівнює одному з цих елементів. Під час виконання POST отримує атрибути value різних опцій, вибраних у комбінованому списку.
- рядок 19: рядки символів, які будуть заповнювати список select3
- рядок 20: пов’язаний із тегом radio у формі. Його значення використовується для позначення одного з перемикачів — того, у якого атрибут value дорівнює цьому значенню. Під час виконання POST отримує значення вибраної кнопки радіо.
- рядок 21: різні назви та значення перемикачів.
- рядок 22: пов’язаний з тегом checkbox у формі. Його початкове значення використовується для встановлення/зняття галочки. Під час виконання POST отримує значення true, якщо поле було позначено, і false — у протилежному випадку.
- рядок 23: пов'язаний з тегом checkboxlist у формі. Початкові значення в таблиці визначають відповідні прапорці, які слід встановити. Будуть встановлені ті прапорці, у яких атрибут value дорівнює одному з цих початкових значень. Під час виконання POST отримує атрибути value різних позначених полів.
- рядок 24: символьні рядки, які будуть використовуватися як назви полів у checkboxlist.
- рядок 25: пов'язаний із прихованим полем hidden. Його початкове значення визначатиме значення прихованого поля. Під час виконання POST отримає те саме значення, оскільки користувач не має можливості його змінити.
- рядок 26: пов’язаний із тегом submit. Під час виконання POST отримує напис кнопки. Без цього поля можна обійтися.
- Методи в рядках 29, 34 та 39 будуть прокоментовані трохи далі.
9.6. Екран [Form.JSP] — розділ «Підтвердження»
Погляд [Form.JSP] має розділ «Підтвердження введених даних», який ще не розглядався:
![]() |
Її код такий:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
...
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="hidden"/>
</tr>
</table>
</body>
</html>
- рядок 13: відображає значення поля [Form].textfield
- рядок 17: відображає значення поля [Form].password
- рядок 21: відображає значення поля [Form].textarea
- рядок 25: відображає значення поля [Form].select1
- рядок 29: відображає значення поля [Form].select2
- рядок 33: відображає значення масиву [Form].select3. Для цього використовується метод [Form].getSelect3SelectedValues.
- рядок 37: виводить значення поля [Form].radio
- рядок 41: виводить значення поля [Form].checkbox
- рядок 45: відображає значення масиву [Form].checkboxlist. Для цього використовується метод [Form].getCheckboxlistSelectedValues.
- рядок 49: відображає значення поля [Form].hidden
9.7. Дія [Form] — частина підтвердження
Згадані вище методи getSelect3SelectedValues та getCheckboxlistSelectedValues визначені у класі [Form]:
// значення, вибрані в полі select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// значення, вибрані у полі checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// допоміжний метод
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
Вони просто об'єднують елементи масивів, які потрібно відобразити.
9.8. Тестування
Під час виконання проекту в NetBeans з’являється така початкова сторінка:
![]() |
Значення, що відображаються в [1] та [2], походять від початкових значень полів дії [Form]. Розглянемо кілька прикладів:
private String textarea = "ligne1\nligne2\n";
Значення поля textarea пояснює відображення [1A] та [2A].
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
Значення поля select3Values пояснює вміст списку в [1B]. Значення поля select3 пояснює елементи, вибрані в [1B] та відображені в [2B].
Якщо ми введемо інші значення у форму та підтвердимо її, введені значення будуть відправлені у відповідні поля дії [Form]. Потім знову відобразиться вікно [Form.JSP]. Отже, ми маємо ту саму ситуацію, що й раніше, за винятком того, що початкові значення були замінені на відправлені. Ось приклад:
![]() | ![]() |
9.9. Дія [Form1] та представлення [Form1.JSP]
Файл конфігурації [example.xml] налаштовує таку дію [Form1]:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.JSP</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.JSP</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.JSP</result>
</action>
</package>
</struts>
У рядках 11–13 виклик дії [Form1] генерує представлення [Form1.JSP].
Дія [Form1] виглядає наступним чином:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form1 extends ActionSupport{
// конструктор без параметрів
public Form1() {
}
// поля форми
private Data data=new Data();
/**
* @return the data
*/
public Data getData() {
return data;
}
/**
* @param data the data to set
*/
public void setData(Data data) {
this.data = data;
}
}
Дія [Form1] ідентична дії [Form], за винятком того, що її модельна частина була винесена в дочірній клас — клас [Data], рядок 11. Клас [Data] має такий вигляд:
package example;
public class Data {
// конструктор без параметрів
public Data() {
}
// поля форми
private String textfield = "texte";
private String password = "secret";
private String textarea = "ligne1\nligne2\n";
private String select1 = "zéro";
private String[] select1Values = new String[]{"zéro", "un", "deux"};
private String select2 = "trois";
private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String radio="bleu";
private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
private Boolean checkbox = false;
private String[] checkboxlist = new String[]{"vélo", "bus"};
private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
private String hidden = "initial";
private String submitText;
// значення, вибрані у полі select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// значення, вибрані у полі checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// допоміжний метод
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// методи getter та setter
....
}
У дії [Form] ми бачимо ті самі поля, що були оголошені раніше.
Цілком логічно, що представлення [Form1.JSP] схоже на представлення [Form.JSP]:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="data.textfield" key="Form.textfield" />
<s:password name="data.password" key="Form.password"/>
<s:textarea name="data.textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="data.select1" list="data.select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="data.select2" size="3" list="data.select2Values" key="Form.select2"/>
<s:select name="data.select3" size="3" list="data.select3Values" key="Form.select3" multiple="true"/>
<s:radio name="data.radio" list="data.radioValues" key="Form.radio"/>
<s:checkbox name="data.checkbox" key="Form.checkbox"/>
<s:checkboxlist name="data.checkboxlist" list="data.checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="data.hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="data.submitText"/>
</s:form>
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="data.textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="data.password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="data.textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="data.select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="data.select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="data.select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="data.radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="data.checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="data.checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="data.hidden"/>
</tr>
</table>
</body>
</html>
Різницю між поданнями [Form] та [Form1] можна проілюструвати на прикладі рядка 27, наведеного нижче:
<s:textfield name="data.textfield" key="Form.textfield" />
Поле введення пов’язане для читання та запису з полем data.textfield дії [Form1]. Нагадаємо, що після виконання властивості дії [Form1] стають доступними для подання. Таким чином, попередній атрибут name буде обчислено як [Form1].getData().getTextField(). Отже, обидва попередні методи get повинні існувати.
9.10. Дія [Form2] та представлення [Form2.JSP]
Файл конфігурації [example.xml] налаштовує таку дію [Form2]:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.JSP</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.JSP</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.JSP</result>
</action>
</package>
</struts>
У рядках 14–16 виклик дії [Form2] генерує представлення [Form2.JSP].
Дія [Form2] виглядає наступним чином:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class Form2 extends ActionSupport implements ModelDriven {
// конструктор без параметрів
public Form2() {
}
// модель дії
public Object getModel() {
return new Data();
}
}
- рядок 6: дія [Form2] реалізує інтерфейс [ModelDriven]. Потрібно реалізувати лише один метод — метод getModel у рядку 12. Він повертає екземпляр класу [Data], який ми розглядали раніше.
Те, що дія [Form2] реалізує інтерфейс [ModelDriven], має такий наслідок: вид, що відображається після дії [Form2], має прямий доступ до властивостей моделі дії [Form2], яка повертається методом getModel(). Таким чином, представлення [Form2.JSP] повертається до того стану, в якому воно перебувало під час виконання початкової дії [Form]:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="textfield" key="Form.textfield" />
<s:password name="password" key="Form.password"/>
<s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
<s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
<s:radio name="radio" list="radioValues" key="Form.radio"/>
<s:checkbox name="checkbox" key="Form.checkbox"/>
<s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="submitText"/>
</s:form>
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="hidden"/>
</tr>
</table>
</body>
</html>
Таким чином, рядок 27, який раніше мав вигляд:
<s:textfield name="data.textfield" key="Form.textfield" />
знову стає:
<s:textfield name="textfield" key="Form.textfield" />
Перевага розміщення моделі поза межами подання полягає в тому, що така архітектура чіткіше розмежовує функціональні можливості кожного елемента архітектури MVC. Модель M чітко ідентифікується класом. Крім того, модель може існувати ще до появи дій. Так, якщо веб-додаток управляє базою даних осіб, ймовірно, що клас Personne вже існує. Якщо дія пропонує форму введення даних для створення нової особи, модель цієї дії вже готова: це клас Personne.
Ми побачили, як просто було перейти від дії [Form] до дії [Form2]:
- модель M подання V була інкапсульована в окремий клас
- дія, яка генерує вигляд, що використовує цю модель, реалізує інтерфейс ModelDriven із методом getModel, який повертає екземпляр моделі M. Отже, цю дію можна розглядати як розширення контролера C у Struts 2 — класу FilterDispatcher.
Читач зможе застосувати цей підхід до будь-якої дії, описаної далі.






