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 属性的值是一个字符串数组,用于生成选项的值和标签。关联的模板是以下 [Form] 操作中的 select1 字段:
private String select1 = "jaune";
该字段与名为 select1 的标签相关联,支持读写操作。在写入操作中,所选选项的值将被写入字段 select1。在读取操作中,字段 select1 的值用于确定所选选项。 在此,字段 select1 的值 jaune 用于选择标签 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 定义。操作 [Form] 中的字段 couleurs 定义如下:
private Couleur[] couleurs;
类 [Couleur] 定义如下:
package example;
public class Couleur {
// 字段
private String id;
private String nom;
// 构造函数
public Couleur(){
}
// 获取器和设置器
...
}
该类包含两个字段,名称分别为 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 字段必须为数组类型。 第22行的list属性是一个字典,其键生成复选框的value属性,其值则生成这些复选框的标签。 操作 [Form] 中的字段 checkboxlist1 如下所示:
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)
右侧单元格中的文本由操作 [Form] 中的方法 getSelect2SelectedValues 生成:
// 下拉列表中的选定值
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;
}
// 获取器和设置器
...
}
该操作中未找到 execute 方法。 因此,实际执行的是父类 ActionSupport 中的方法 execute。该方法不执行任何操作,仅返回导航键 SUCCESS。
10.5. 测试
建议读者测试应用程序 [exemple-08]。
