Struts2 <s:doubleselect>级联下拉框 详解析
运行环境:myeclipse8.6+jboss5.1+jvm1.6
先看最后目录结构:

直接上源码:
complexFormTag.jsp:
<%@ page language="java" contentType="text/html; charset=gb2312"pageEncoding="gb2312"%> <%@ taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>复杂表单标签使用范例</title> <s:head /> </head> <body> <h3 align="left">doubleselect标签使用范例</h3> <p> <s:form name="doubleselectExample"> <s:doubleselect label="材料" headerValue="" headerKey="0" list="itemList" listKey="itemId" listValue="item" doubleName="abc" doubleList="materialMap.get(top.itemId)" doubleListKey="materialId" doubleListValue="material" /> </s:form> </p> </body> </html>
解析:
若不使用Struts2,则需要结合JavaScript和HTML标签共同开发完成此功能。
doubleselect标签的功能是提供两个有级联关系的下拉框。用户选中第一个下拉框中的某选项,则第二个下拉框中的选项根据第一个下拉框被选中的某选项内容来决定它自己的下拉框选项内容,产生联动效果。
对于代码"materialMap.get(top.itemId)",其中的top返回的是材料类别map集合的value即材料list集合中的材料类对象实例。
最后面会对top更进一步解释。
注意:<s:doubleselect/>标签必须放在<s:form>中,放在普通<form>中会出错,而且s:form必须指定name属性。
另外,希望页面美观的话,希望s:doubleselect标签和左边的字对齐,则指定s:doubleselect属性theme="simple"
希望两个select排成一行(默认是上下行的),则在<s:form></s:form>间加入css样式:
<style> 
      .nobr br{display:none}   
  </style>
然后在用<div class="nobr"></div>把<s:doubleselect .. />包起来就可以了!
下面是doubleselect标签的属性列表:
 
下面通过一张图形象的表示联动关系:
 
对应的组件:
最后,两个下拉框要联动起来,靠的是“ItemId”与下面"Integer类型变量"的一一对应关系。

<s:doubleselect ...
list="itemList" listKey="itemId" listValue="item"
doubleList="materialMap.get(top.itemId)"doubleListKey="materialId"doubleListValue="material" />
注意,上面的两相同的itemId,这里应该必须一致。
complexFormTagAction.java:
package action;  import java.util.ArrayList;  import java.util.HashMap;  import java.util.List;  import java.util.Map;  import com.opensymphony.xwork2.ActionSupport;  import model.*;    public class ComplexFormTagAction extends ActionSupport {   //级联第一个下拉框数据   private List<Item> itemList;   //级联第二个下拉框数据   private Map<Integer, List<Material>> materialMap;     public String execute() throws Exception {    itemList = new ArrayList<Item>();      //循环新建10个类别    for (int j = 0; j < 10; j++) {     Item item = new Item();     item.setItemId(j + 1);     item.setItem("类别" + (j + 1));     itemList.add(item);    }        materialMap = new HashMap<Integer, List<Material>>();    //循环新建每个类别中的10个材料    for (int j = 0; j < 10; j++) {     List<Material> materialList = new ArrayList<Material>();     for (int i = 0; i < 10; i++) {      Material material = new Material();      material.setMaterialId(i);      material.setMaterial("类别" + (j + 1)+"-->"+"材料"+(i + 1));      materialList.add(material);     }     materialMap.put((j + 1), materialList);    }    return SUCCESS;   }     public Map<Integer, List<Material>> getMaterialMap() {    return materialMap;   }     public void setMaterialMap(Map<Integer, List<Material>> materialMap) {    this.materialMap = materialMap;   }     public List<Item> getItemList() {    return itemList;   }     public void setItemList(List<Item> itemList) {    this.itemList = itemList;   }  } Material.java:
package model;    public class Material implements java.io.Serializable {   // Fields   private int materialId;   private String material;     public Material() {}     public int getMaterialId() {    return this.materialId;   }     public void setMaterialId(int materialId) {    this.materialId = materialId;   }     public String getMaterial() {    return this.material;   }     public void setMaterial(String material) {    this.material = material;   }  } Item.java:
package model;    public class Item implements java.io.Serializable {   private int itemId;    private String item;      public Item() {}     public int getItemId() {    return itemId;   }     public void setItemId(int itemId) {    this.itemId = itemId;   }     public String getItem() {    return this.item;   }     public void setItem(String item) {    this.item = item;   }  } struts.xml:
<?xml version="1.0" encoding="gb2312"?> <!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.i18n.encoding" value="gb2312"/> <package name="OGNLTAG" extends="struts-default"> <action name="complexFormTag" class="action.ComplexFormTagAction"> <result name="success">/jsp/complexFormTag.jsp</result> </action> </package> </struts>
运行http://localhost:8080/OGNLTAG/jsp/complexFormTag.action
注:后缀是.action而非.jsp,否则异常:
The requested list key 'itemList' could not be resolved as a collection/array/map/enumeration/iterator type.
因为直接访问jsp页面的话,要先经过struts.xml导航,然后才转到调用Action类处理;这样的话"itemList"就没有完成初始化,故而出现上述异常。若直接“.action”去访问Action类的话,就完成初始化操作了,故而" 'itemList' can be resolved as a collection"。
输出结果:

------------------------------------------------------------------------------
最后通过<s:debug />看一下调试结果中的“值栈”:
Struts ValueStack Debug
Value Stack Contents
 
注意上图中materialMap和itemList这两个Action类中有且仅有的两实例属性。从上面的图片可以理解doubleList="materialMap.get(top.itemId)"中的top,它的意思是:the value at the top of the stack 。
用语句<s:property value="top" />,会输出:action.ComplexFormTagAction@ 1db6a20
<s:property value="materialMap" />,会输出:{1=[model.Material@.....],2=[...],...,10=[...] }
(不用"#",也就是直接从“值栈”中取值,此处等效于value="top.materialMap")
<s:property value="itemList" />,会输出:[model.Item@......,model.Item@...,.......]
测试<s:property value="top.itemId" />输出为空,是因为itemId这个值是要根据listKey才能确定出来的。
可以上面语句看出:top就是指上面图片中的“Object列”的对象,它有些“Property”,如 texts、materialMap、actionErrors . . .。
list="itemList" listKey="itemId" listValue="item" doubleName="abc" doubleList="materialMap.get(top.itemId)"
top.itemId:top代表的就是list即"itemList"当前选中的对象, 所以top.itemId对应的就是当前选中的对象Item的ID, materialMap.get(top.itemId)即根据当前选中的对象Item中的ID来取出第二级下拉框的数据集合。
