用selectOneMenu标签开发级联选择

  用selectOneMenu标签开发级联下拉选择
岳乡成

环境:jdk1.6.0、jboss-4.2.3.GA、jboss-seam-2.1.1.GA 、My-SQL-5.0.8

一、标签说明
1. 概要
级联下拉选择是最常用的组件之一,它一般是用Ajax来实现的。利用<h:selectOneMenu>,<s:selectItems>,及<a:support>可以很方便的开发级联下拉选择。如下图所示为一个用<h:selectOneMenu>做的级联下拉选择的示例。

                            级联下拉选择示例
   上图中选择省份,可以动态的得到该省的市(地区),如果再选择了市可以动态得到该市的所有县(区)。
2. 标签属性
<h:selectOneMenu>
属性名称 描述
id 组件标识符
value 下拉框当前的值
required 是否是必输项
<s:selectItems>
从一个List、Set、DataModel或者Array中创建一个 List<SelectItem> 。
属性名称 描述
id 组件标识符
value 一个EL表达式,指定支持 List<SelectItem> 的数据
var 定义迭代期间保存当前对象的本地变量的名称
label 渲染 SelectItem 时要使用的标签。可以参考 var 变量
disabled 如果为true,SelectItem 将被取消渲染。可以参考 var 变量
noSelectionLabel 指定(可选)标签放在列表的顶部(如果也指定 required="true",那么选择这个值将导致验证出错)
hideNoSelectionLabel 如果为true,选择一个值时,noSelectionLabel 将被隐藏
<a:support>
Ajax4jsf中的一个标签,该标签的功能是对标准的jsf组件添加Ajax功能支持。
属性名称 描述
id 组件标识符
event 父组件的JavaScript事件属性的名称(onclick、onchange等)
actionlistener 方法绑定,当该组件被Ajax请求激活时,将调用该监听器方法处理该事件。该方法必须为public的并且接受一个AjaxEvent参数,返回void

二、示例开发
1. JSF Web页面
<s:div id="chooseareadiv">                             
             <table class="class_tab1" cellspacing="0" bordercolordark="ffffff" cellpadding="1" bordercolorlight="#C0CFE0" border="1" width="100%">                           
            <tr>
            <td width="10%" align="center">
            <h:outputLabel id="provincesLabel" value="省份(必须):"></h:outputLabel>
            </td>
            <td width="15%" align="center">
               <h:selectOneMenu id="provincesSel" required="false" value="#{temp.province}">
                    <s:selectItems noSelectionLabel="-请选择省份-" value="#{locationUtil.provincesList}" var="item" label="#{item.category_name}" itemValue="#{item.category_id}"/>                      
                    <a:support event="onchange" actionListener="#{entProfileHome.changeProvince}" reRender="citySel,districtSel"/>  
                </h:selectOneMenu>
            </td>
            <td  width="20%" align="center">
            <h:outputLabel id="cityLabel" value="市(地区)(必须):"></h:outputLabel>
            </td>
            <td  width="15%" align="center">   
                <h:selectOneMenu id="citySel" required="false" value="#{temp.city}"  >  
                    <s:selectItems noSelectionLabel="-请选择城市-" value="#{locationUtil.getCities(entProfileHome.temp.province)}" var="item" label="#{item.category_name}" itemValue="#{item.category_id}"/>  
                    <a:support event="onchange" actionListener="#{entProfileHome.changeCity}" reRender="districtSel"/>  
                </h:selectOneMenu>
            </td>
            <td width="15%" align="center">
            <h:outputLabel id="districtLabel" value="县(区)(必须):"></h:outputLabel>
            </td>
            <td width="15%" align="center">  
    <h:selectOneMenu id="districtSel" required="false" value="#{temp.district}">  
        <s:selectItems  noSelectionLabel="-请选择区-" value="#{locationUtil.getDistricts(entProfileHome.temp.city)}" var="item" label="#{item.category_name}" itemValue="#{item.category_id}"/>  
    </h:selectOneMenu>
            </td>
            <td align="center">
            <a:commandButton  id="addEhrUserButton" value="新建" action="#{Personalinfometion.createEhrUser(entProfileHome.temp.district)}"   onclick="if(!validationDistrict()) return false;"  reRender="addpersonalinfodiv" />           
            </td>            
            </tr>
             </table>
             </s:div>
以上页面代码中用到三个类(1)temp类,它是用于获取省、市、县下拉列表框的当前选择的值。(2)locationUtil类,它是用于获取省、市、县下拉列表框中所有的内容,及发生了onchange事件后的重新获得市、县下拉列表框的内容。(3)entProfileHome类。它负责当一个下拉框内容该变时清理它下一级下拉列表框的内容。
2. Java类, Session Bean及接口
EntProfile类定义如下:
/**
* <p>WeeklyPlanAction</p>
*
*  版权 (c) 2009
*
* <p>CIB</p>
*
* 文件历史
* 日期                  作者            描述
* 2009-06-21        xiangcheng.yue      创建
*
*/

package com.tower.ehr.personalinfo;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;

@Name("temp")
@Scope(ScopeType.SESSION)
public class EntProfile{
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getDistrict() {
return district;
}
public void setDistrict(String district) {
this.district = district;
}
private String province;
private String city;
private String district;

}
entProfileHome类定义如下:
/**
* <p>WeeklyPlanAction</p>
*
*  版权 (c) 2009
*
* <p>CIB</p>
*
* 文件历史
* 日期                  作者            描述
* 2009-06-21        xiangcheng.yue      创建
*
*/
package com.tower.ehr.personalinfo;

import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.framework.EntityHome;

@Name("entProfileHome")
public class EntProfileHome extends EntityHome<EntProfile> {  
 
      
    @In(required=false)
    @Out(required=false)
    private EntProfile temp;  
      
    /** 
     * 省份被选择修改后的ajax事件动作,清空已关联的市和县区数据 
     */ 
    public void changeProvince(){  
        temp.setCity(null);  
        temp.setDistrict(null);  
    }  
    /** 
     * 市被选择修改后的ajax事件动作,清空已关联的县区数据 
     */ 
    public void changeCity(){
        temp.setDistrict(null);  
    }
    public void startEdit(){
        temp = new EntProfile();  
        temp.setProvince(getInstance().getProvince());  
        temp.setCity(getInstance().getCity());  
        temp.setDistrict(getInstance().getDistrict());  
          
    }  
      
    public void updateEdit(){  
        getInstance().setProvince(temp.getProvince());  
        getInstance().setCity(temp.getCity());  
        getInstance().setDistrict(temp.getDistrict());  
       
        update();  
        temp = null;  
    }  
      
   
   
    @Override 
    @Begin 
    public void create() {  
        super.create();  
    }  
 
    public EntProfile getTemp() {  
        return temp;  
    }  
    public void setTemp(EntProfile temp) {  
        this.temp = temp;  
    }   
}
Session bean类personalinfo的接口定义如下:
package com.tower.ehr.personalinfo.Impl;

import java.util.List;
import javax.ejb.Local;

import com.tower.ehr.entitybean.Category;

@Local
public interface LocationUtilImpl {
public List<Category> getProvincesList();
public List<Category> getCities(String province);
public List<Category> getDistricts(String city);
public void init();
public void destroy();
}
Session bean类personalinfo定义如下:
/**
* <p>LocationUtil</p>
*
*  版权 (c) 2009
*
* <p>CIB</p>
*
* 文件历史
* 日期                  作者            描述
* 2009-06-01        xiangcheng.yue      创建
*
*/

package com.tower.ehr.personalinfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;

import com.tower.ehr.entitybean.Category;
import com.tower.ehr.personalinfo.Impl.LocationUtilImpl;

@Stateful
@Name("locationUtil")
@Scope(ScopeType.SESSION)
/**
* * 创建该类是为了实现personalinfo中的省市县的级联。
*/
public class LocationUtil implements LocationUtilImpl{
/** 省的对象List. */
List<Category> provincesList = new ArrayList<Category>();
/** 由省的名称及所有该省的市的List组成的Map. */
private Map<String, List<Category>> map_cities = new HashMap<String, List<Category>>();
/** 由市的名称及所有该市的县的List组成的Map. */
private Map<String,  List<Category>> map_districts = new HashMap<String,  List<Category>>();
/** 实例化EntityManager。 */

@PersistenceContext
private EntityManager em;
/**
* 取得所有省份数据
*
* @return
*/
public List<Category> getProvincesList() {
return provincesList;
}

/**
* 根据省取得所有市数据
*
* @param province
* @return
*/
public List<Category> getCities(String province) {
return map_cities.get(province);
}

/**
* 根据市取得所有区县数据
*
* @param city
* @return
*/
public List<Category> getDistricts(String city) {
return map_districts.get(city);
}

/**
* @since 2009-06-01 在应用启动时取省市县的数据。
* @return
* @throws
*/
@Observer("org.jboss.seam.postInitialization")
//@Create
public void init() {
/** 市的对象List. */
List<Category> citiesList = new ArrayList<Category>();

    provincesList = getProvinces();


for(int i = 0;i<provincesList.size();i++){
List<Category> cityList = getCitiesByProvincesId(provincesList.get(i).getCategory_id());
if(cityList.size()>0){
map_cities.put(provincesList.get(i).getCategory_id(), cityList);
citiesList.addAll(cityList);
}
}


for(int i = 0;i<citiesList.size();i++){
List<Category> districtsList = getDistrictsByCityId(citiesList.get(i).getCategory_id());
if(districtsList.size()>0){
map_districts.put(citiesList.get(i).getCategory_id(), districtsList);
}
}
}


/**
* @since 2009-06-01
* 得到所有省的list。
* @return List<Category>
* @throws
*/
public  List<Category> getProvinces() {
List<Category> results = em.createQuery(
"select td from Category td where td.parent_category_id is null"
).getResultList();
return results;
}
/**
* @since 2009-06-01
* 通过省的Id得到所有市的list。
* @return List<Category>
* @throws
*/
public  List<Category> getCitiesByProvincesId(String ProvincesId) {
List<Category> results = em.createQuery(
"select td from Category td where td.parent_category_id = "
+ ProvincesId).getResultList();
return results;
}

/**
* @since 2009-06-01
* 通过市的Id得到所有县的list。
* @return List<Category>
* @throws
*/

public   List<Category> getDistrictsByCityId(String CityId) {
List<Category> results = (List<Category>) em.createQuery(
"select td from Category td where td.parent_category_id = "
+ CityId).getResultList();
return results;
}
/**
* @since 2009-06-01
* 效验是否选择了县的下拉框。
* @return boolean
* @throws
*/
public boolean validationDistrict(){
// if(districtId!=null&&districtId!=""){
// return false;
// }
return true;

}
@Remove
public void destroy() {
}
}

4.小结。
    利用<h:selectOneMenu>,<s:selectItems>,及<a:support>标签制作级联下拉列表过程非常简单,只需要掌握<h:selectOneMenu>,<s:selectItems>,<a:support>的几个属性及深入理解Map的key-value的属性即可。希望参考本文档的读者能有所收获,谢谢。

你可能感兴趣的:(bean,Ajax,jboss,JSF,seam)