Skip to content

10. 示例 08 - 与列表关联的标签

以下示例重点介绍用于显示列表的标签。我们在前一个示例中已经遇到过它们:下拉列表、复选框和单选按钮。测试表单如下所示:

Image

Image

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 代码:

1
2
3
4
5
<select name="select1" size="1" id="Form_select1">
    <option value="vert">vert</option>
    <option value="jaune" selected="selected">jaune</option>
    <option value="rouge">rouge</option>
</select>

list 属性的值是一个字符串数组,用于生成选项的值和标签。关联的模型是以下 [Form] 操作中的 select1 字段:


  private String select1 = "jaune";

该字段与名为 select1 的标签相关联,具有读写权限。写入时,所选选项的值将被注入到 select1 字段中。读取时,select1 字段的值将用于确定所选选项。在此,select1 字段中的值 "yellow" 被用于在 select1 标签中选择值为 "yellow" 的选项。 这就是为什么在第 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 代码如下:

1
2
3
4
5
6
7
<select name="select3" size="3" id="Form_select3" multiple="multiple">
    <option value="01" selected="selected">vert(01)</option>
    <option value="02">jaune(02)</option>
    <option value="03" selected="selected">rouge(03)</option>
    <option value="04">blanc(04)</option>
    <option value="05">noir(05)</option>
</select>

该操作中的关联字段如下:


  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" />

选项列表由 list 属性定义的 colors 字段生成。[Form] 操作的 colors 字段定义如下:


private Couleur[] couleurs;

[Color] 类的定义如下:


package example;
 
public class Couleur {
 
  // fields
  private String id;
  private String nom;
 
  // manufacturer
  public Couleur(){
  }
 
  // getters and setters
...  
}

它有两个字段,分别名为 idname。在 select5 标签中,我们设置了 listKey="id" 和 listValue="name"这意味着 id 字段将作为选项的值,而 name 字段将作为标签。请记住,提交的是选项的值。它们将被提交到以下 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 代码:

<input type="checkbox" name="checkboxlist1" value="01" id="checkboxlist1-1" checked="checked"/>
<label for="checkboxlist1-1" class="checkboxLabel">vert(01)</label>
<input type="checkbox" name="checkboxlist1" value="02" id="checkboxlist1-2"/>
<label for="checkboxlist1-2" class="checkboxLabel">jaune(02)</label>
<input type="checkbox" name="checkboxlist1" value="03" id="checkboxlist1-3" checked="checked"/>
<label for="checkboxlist1-3" class="checkboxLabel">rouge(03)</label>
<input type="checkbox" name="checkboxlist1" value="04" id="checkboxlist1-4"/>
<label for="checkboxlist1-4" class="checkboxLabel">blanc(04)</label>
<input type="checkbox" name="checkboxlist1" value="05" id="checkboxlist1-5"/>
<label for="checkboxlist1-5" class="checkboxLabel">noir(05)</label>

所有复选框的名称均为 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 代码如下:

1
2
3
4
5
<input type="radio" name="radio1" id="Form_radio101" checked="checked" value="01"/><label for="Form_radio101">vert(01)</label>
<input type="radio" name="radio1" id="Form_radio102" value="02"/><label for="Form_radio102">jaune(02)</label>
<input type="radio" name="radio1" id="Form_radio103" value="03"/><label for="Form_radio103">rouge(03)</label>
<input type="radio" name="radio1" id="Form_radio104" value="04"/><label for="Form_radio104">blanc(04)</label>
<input type="radio" name="radio1" id="Form_radio105" value="05"/><label for="Form_radio105">noir(05)</label>

所有单选按钮都使用相同的名称:radio1。每次只能选择一个单选按钮。因此,仅会提交一个值:即所选单选按钮的值。列表字典中的键用于生成单选按钮的 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";

以上内容涵盖了表单的数据输入部分。此外还有一个确认部分,与前一个示例中的类似:它用于确认提交的值。我们仅对以下几行进行说明:


      <tr>
        <td><s:text name="Form.select2"/></td>
        <td><s:property value="select2SelectedValues"/>
</tr>

这在视觉上对应于以下内容:

Image

左侧单元格中的文本来自 [messages.properties] 文件:


Form.select2=2-select2 (multiple=true, size=3)

右侧单元格中的文本由 [Form] 操作的 getSelect2SelectedValues 方法生成:


// valeurs sélectionnées dans listes déroulantes
  public String getSelect2SelectedValues() {
    return getArrayValue(select2);
  }
 
  // méthodes utilitaires
  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 {
 
  // form fields
  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;
 
  // constructor without parameters
  public Form() {
    // init color dictionary
    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)");
 
    // init array of objects Color
    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++;
    }
  }
 
  // values selected from drop-down lists
  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);
  }
 
  // utility methods
  public String getArrayValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
  }
 
  // getters and setters
   ...
}

此操作中没有 execute 方法。因此,将执行父类 ActionSupportexecute 方法。该方法不执行任何操作,仅返回 SUCCESS 导航键。

10.5. 测试

欢迎读者测试 [example-08] 应用程序。