10. Приклад 08 — Теги, пов’язані зі списками
У наступному прикладі розглядаються теги, що відображають списки. Ми вже зустрічали їх у попередньому прикладі: випадаючий список, прапорці та перемикачі. Тестова форма матиме такий вигляд:
![]() | ![]() |
10.1. Проєкт NetBeans
Проект NetBeans виглядає так:
![]() |
- у [1] — дія, а в [2] — відповідний вигляд.
Файл [example/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>
</package>
</struts>
У рядках 8–9 показано, що виклик URL [/example/Form.action] генерує представлення [/example/Form.JSP]. Отже, дія [Form] буде відповідати за побудову шаблону подання [Form.JSP].
10.2. Файл інтернаціоналізованих повідомлень
Файл [messages.properties] з інтернаціоналізованими повідомленнями має такий вигляд:
Form.francais=Fran\u00E7ais
Form.anglais=Anglais
Form.titre=Struts 2 - les tags \u00E0 valeurs multiples
Form.message=Struts 2 - les tags \u00E0 valeurs multiples
Form.langues=langues
Form.select1=1-select1 (multiple=false, size=1)
Form.select2=2-select2 (multiple=true, size=3)
Form.select3=3-select3 (multiple=true, size=3)
Form.select4=4-select4 (multiple=true, size=3)
Form.select5=5-select5 (multiple=true, size=3)
Form.checkboxlist1=6-checkboxlist1
Form.checkboxlist2=7-checkboxlist2
Form.checkboxlist3=8-checkboxlist3
Form.radio1=9-radio1
Form.radio2=10-radio2
Form.radio3=11-radio3
Form.submitText=Valider
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.select1=1-select1 (multiple=false, size=1)
Confirmation.select2=2-select2 (multiple=false, size=3)
Confirmation.select3=3-select3 (multiple=true, size=3)
Confirmation.select4=4-select4 (multiple=true, size=3)
Confirmation.select5=5-select5 (multiple=true, size=3)
Confirmation.checkboxlist1=6-checkboxlist1
Confirmation.checkboxlist2=7-checkboxlist2
Confirmation.checkboxlist3=8-checkboxlist3
Confirmation.radio1=9-radio1
Confirmation.radio2=10-radio2
Confirmation.radio3=11-radio3
Вигляд [Form.JSP] використовує ці повідомлення.
10.3. Вигляд [Form.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:select name="select1" list="{'vert','jaune','rouge'}" size="1" key="Form.select1"/>
<s:select name="select2" list="{'vert','jaune','rouge'}" size="3" key="Form.select2" multiple="true"/>
<s:select name="select3" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" size="3" key="Form.select3" multiple="true"/>
<s:select name="select4" list="dico" size="3" key="Form.select4" multiple="true"/>
<s:select name="select5" list="couleurs" listKey="id" listValue="nom" size="3" key="Form.select5" multiple="true" />
<s:checkboxlist name="checkboxlist1" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" key="Form.checkboxlist1"/>
<s:checkboxlist name="checkboxlist2" list="dico" key="Form.checkboxlist2"/>
<s:checkboxlist name="checkboxlist3" list="couleurs" listKey="id" listValue="nom" key="Form.checkboxlist3" />
<s:radio name="radio1" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" key="Form.radio1"/>
<s:radio name="radio2" list="dico" key="Form.radio2"/>
<s:radio name="radio3" list="couleurs" listKey="id" listValue="nom" key="Form.radio3" />
<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.select1"/></td>
<td><s:property value="select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.select4"/></td>
<td><s:property value="select4SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.select5"/></td>
<td><s:property value="select5SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist1"/></td>
<td><s:property value="checkboxlist1SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist2"/></td>
<td><s:property value="checkboxlist2SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist3"/></td>
<td><s:property value="checkboxlist3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio1"/></td>
<td><s:property value="radio1"/>
</tr>
<tr>
<td><s:text name="Form.radio2"/></td>
<td><s:property value="radio2"/>
</tr>
<tr>
<td><s:text name="Form.radio3"/></td>
<td><s:property value="radio3"/>
</tr>
</table>
</body>
</html>
Розглянемо різні теги для введення даних у формі:
- рядок 27: тег <s:select>:
<s:select name="select1" list="{'vert','jaune','rouge'}" size="1" key="Form.select1"/>
Цей тег згенерує такий HTML-код:
Значення атрибута list — це масив рядків, який використовується для генерації значень та назв опцій. Відповідним шаблоном є поле select1 у такій дії [Form]:
private String select1 = "jaune";
Це поле пов’язане з тегом select1 як для читання, так і для запису. Під час запису значення вибраної опції буде вставлено в поле select1. Під час читання значення поля select1 використовується для визначення вибраної опції. У цьому випадку значення jaune поля select1 використовується для вибору опції тегу select1, яке має значення «жовтий». Саме тому в рядку 3 ця опція є вибраною.
- рядок 28
<s:select name="select2" list="{'vert','jaune','rouge'}" size="3" key="Form.select2" multiple="true"/>
Немає принципової різниці з тегом у рядку 27, за винятком того, що тут вибір є множинним. Отже, значення, що передається, є масивом значень — значень вибраних опцій. Поле select2 дії, пов’язаної з формою, має такий вигляд:
private String[] select2 = new String[]{"vert", "rouge"};
Це дійсно масив. Його початкове значення використовується для вибору опцій, значення яких містяться в масиві.
- рядок 29
<s:select name="select3" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" size="3" key="Form.select3" multiple="true"/>
Тут значення атрибута list є словником, ключі якого слугують значеннями для опцій, а відповідні значення — назвами опцій. Згенерований HTML-код має такий вигляд:
Відповідне поле в дії виглядає так:
private String[] select3 = new String[]{"01", "03"};
Ми знову маємо масив значень, оскільки відповідний тег є багатовибірковим. Початкові значення масиву пояснюють, чому опції у рядках 2 та 4 спочатку вибрані.
- рядок 30
<s:select name="select4" list="dico" size="3" key="Form.select4" multiple="true"/>
Тут варіанти зі списку будуть надані шаблоном подання, який у цьому випадку є частиною дії [Form]:
private HashMap<String, String> dico = new HashMap<String, String>();
Ключі словника dico будуть значеннями опцій. Значення словника dico будуть назвами опцій. Поле select4 дії має такий вигляд:
private String[] select4 = new String[]{"1", "3"};
Це масив значень, який отримає значення, передані тегом select4.
- рядок 31
<s:select name="select5" list="couleurs" listKey="id" listValue="nom" size="3" key="Form.select5" multiple="true" />
Список опцій генерується полем couleurs, визначеним атрибутом list. Поле couleurs дії [Form] визначено наступним чином:
private Couleur[] couleurs;
Клас [Couleur] визначено таким чином:
package example;
public class Couleur {
// поля
private String id;
private String nom;
// конструктор
public Couleur(){
}
// методи getter та setter
...
}
У ній є два поля з назвами id та nom. У тезі select5 міститься listKey="id" listValue="nom".. Це означає, що поле id слугуватиме значенням для опції, а поле nom — назвою. Нагадуємо, що саме значення опцій заносяться до запису. Вони будуть занесені до наступного поля select5:
private String[] select5 = new String[]{"1", "3"};
- рядок 32
<s:checkboxlist name="checkboxlist1" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" key="Form.checkboxlist1"/>
Цей тег згенерує такий HTML-код:
Усі прапорці мають назву checkboxlist1. Оскільки кожен із них можна встановити, може бути надіслано кілька параметрів checkboxlist1. Тому поле checkboxlist1 у формі має бути типу масиву. Атрибут list у рядку 22 є словником, ключі якого генерують атрибути value прапорців, а значення — назви цих самих прапорців. Поле checkboxlist1 дії [Form] має такий вигляд:
private String[] checkboxlist1 = new String[]{"01", "03"};
- рядок 33
<s:checkboxlist name="checkboxlist2" list="dico" key="Form.checkboxlist2"/>
Цей тег працює так само, як тег select4, розглянутий раніше. Відповідне поле в дії має такий вигляд:
private String[] checkboxlist2 = new String[]{"1", "3"};
- рядок 34
<s:checkboxlist name="checkboxlist3" list="couleurs" listKey="id" listValue="nom" key="Form.checkboxlist3" />
Цей тег працює так само, як тег select5, розглянутий раніше. Відповідне поле checkboxlist3 у дії є таким:
private String[] checkboxlist3 = new String[]{"1", "3"};
- рядок 35
<s:radio name="radio1" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" key="Form.radio1"/>
Цей тег за своїм принципом роботи аналогічний тегу select3, розглянутому раніше. Згенерований HTML-код має такий вигляд:
Усі теги мають однакову назву radio1. Можна вибрати лише одну перемикальну кнопку. Отже, надсилається лише одне значення — значення вибраної перемикальної кнопки. Ключі словника list використовуються для генерації атрибутів value перемикачів, тоді як значення словника використовуються для генерації текстів, пов’язаних із цими перемикачами. Поле radio1, пов’язане з цією дією, має такий вигляд:
private String radio1="01";
- рядок 36
<s:radio name="radio2" list="dico" key="Form.radio2"/>
Цей тег за принципом дії працює так само, як тег select4. Поле radio2, пов’язане з цією дією, виглядає так:
private String radio2="1";
- рядок 37
<s:radio name="radio3" list="couleurs" listKey="id" listValue="nom" key="Form.radio3" />
Цей тег за принципом дії працює так само, як тег select5. Поле radio3, пов’язане з цією дією, виглядає так:
private String radio3="1";
Ось і вся частина saisie форми. Існує також частина confirmation, яка аналогічна тій, що була у формі з попереднього прикладу: вона підтверджує відправлені значення. Ми прокоментуємо лише наступні рядки:
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2SelectedValues"/>
</tr>
що візуально відповідає такому:
Текст у лівій комірці взято з файлу [messages.properties]:
Form.select2=2-select2 (multiple=true, size=3)
Текст у правій комірці було згенеровано методом getSelect2SelectedValues дії [Form]:
// значення, вибрані зі списків, що розгортаються
public String getSelect2SelectedValues() {
return getArrayValue(select2);
}
// допоміжні методи
public String getArrayValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
Метод getSelect2SelectedValues перетворює значення масиву select2 у рядок символів.
10.4. Дія [Form]
Коментуючи погляд [Form.JSP], ми представили поля пов’язаної дії [Form]. Код дії [Form] такий:
package example;
import com.opensymphony.xwork2.ActionSupport;
import java.util.HashMap;
public class Form extends ActionSupport {
// поля форми
private String select1 = "jaune";
private String[] select2 = new String[]{"vert", "rouge"};
private String[] select3 = new String[]{"01", "03"};
private String[] select4 = new String[]{"1", "3"};
private String[] select5 = new String[]{"1", "3"};
private HashMap<String, String> dico = new HashMap<String, String>();
private Couleur[] couleurs;
private String[] checkboxlist1 = new String[]{"01", "03"};
private String[] checkboxlist2 = new String[]{"1", "3"};
private String[] checkboxlist3 = new String[]{"1", "3"};
private String radio1="01";
private String radio2="1";
private String radio3="1";
private String submitText;
// конструктор без параметрів
public Form() {
// ініціалізація словника кольорів
dico.put("1", "vert(1)");
dico.put("2", "jaune(2)");
dico.put("3", "bleu(3)");
dico.put("4", "rouge(4)");
dico.put("5", "blanc(5)");
// ініціалізація масиву об’єктів «Колір»
couleurs = new Couleur[dico.size()];
int i = 0;
for (String key : dico.keySet()) {
couleurs[i] = new Couleur();
couleurs[i].setId(key);
couleurs[i].setNom(dico.get(key));
i++;
}
}
// значення, вибрані зі списків, що розгортаються
public String getSelect2SelectedValues() {
return getArrayValue(select2);
}
public String getSelect3SelectedValues() {
return getArrayValue(select3);
}
public String getSelect4SelectedValues() {
return getArrayValue(select4);
}
public String getSelect5SelectedValues() {
return getArrayValue(select5);
}
public String getCheckboxlist1SelectedValues() {
return getArrayValue(checkboxlist1);
}
public String getCheckboxlist2SelectedValues() {
return getArrayValue(checkboxlist2);
}
public String getCheckboxlist3SelectedValues() {
return getArrayValue(checkboxlist3);
}
// допоміжні методи
public String getArrayValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// методи getter та setter
...
}
У цій дії не знайдено методу execute. Отже, виконується метод execute батьківського класу ActionSupport. Цей метод нічого не робить, а лише повертає ключ навігації SUCCESS.
10.5. Тестування
Читачеві пропонується протестувати додаток [exemple-08].


