????? 在程序开发过程中,经常要实现级联的作用,比如:省市区的级联,当下拉列表选择了省之后,在市的下拉的时候就应该是该省下的所有城市,而不是全部饿城市,以此类推在选着市区之后在区域也应该是该市下的市区。
?????? 其实这种级联的方式,完全可以用一颗树表示,比如省是根节点,其他的都是其孩子的方式表示,但是这里我只用下拉列表的方式实现,毕竟有得地方用这种方式还是有点优势,而且不是很复杂。
其实现的步骤如下:
首先看看JS部分:
建立省市区的三个下拉列表comboBox
var pcombo = new Ext.form.ComboBox({ fieldLabel : '所在省', anchor: '80%', forceSelection : true, selectOnFocus: true, triggerAction: 'all', mode: 'local', store: pdatastore, allowBlank: true, maxHeight:180, valueField : 'pid', displayField : 'pname', applyTo : 'pcombo' }); var ccombo = new Ext.form.ComboBox({ fieldLabel : '所在市', anchor: '80%', forceSelection : true, selectOnFocus: true, triggerAction: 'all', mode: 'local', store: cdatastore, allowBlank: true, maxHeight:180, valueField : 'cid', displayField : 'cname', applyTo : 'ccombo' }); var acombo = new Ext.form.ComboBox({ fieldLabel : '所在区', anchor: '80%', forceSelection : true, selectOnFocus: true, triggerAction: 'all', mode: 'local', store: adatastore, allowBlank: true, maxHeight:180, valueField : 'aid', displayField : 'aname', applyTo : 'acombo' });
??这样就定义号了三个级联的comboBox,我这里要实现的是从数据库中加载数据,所有定义一个加载数据的store,其他实现方式如下:
//------------省开始------------------ var precord=[ {name : 'pid',type : 'string'}, {name : 'pname',type : 'string'} ]; var precordHeads = Ext.data.Record.create(precord); var pdatastore = new Ext.data.Store( { proxy:new Ext.data.HttpProxy(new Ext.data.Connection({timeout:0,url:'./json/cascade_findProvinces.action'})), reader : new Ext.data.JsonReader( { root : 'provinces' //后台返回的list集合 }, precordHeads), remoteSort : false }); //----------市开始-------------------- var crecord=[ {name : 'cid',type : 'string'}, {name : 'cname',type : 'string'}, {name : 'pid',type : 'string'} ]; var crecordHeads = Ext.data.Record.create(crecord); var cdatastore = new Ext.data.Store( { proxy:new Ext.data.HttpProxy(new Ext.data.Connection({timeout:0,url:'./json/cascade_findCityByPid.action'})), reader : new Ext.data.JsonReader( { root : 'cities' //后台返回的list集合 }, crecordHeads), remoteSort : false }); //----------区开始-------------------- var arecord=[ {name : 'aid',type : 'string'}, {name : 'aname',type : 'string'}, {name : 'cid',type : 'string'} ]; var arecordHeads = Ext.data.Record.create(arecord); var adatastore = new Ext.data.Store( { proxy:new Ext.data.HttpProxy(new Ext.data.Connection({timeout:0,url:'./json/cascade_findAreaByCid.action'})), reader : new Ext.data.JsonReader( { root : 'areas' //后台返回的list集合 }, arecordHeads), remoteSort : false });
??级联下拉列表需要用到comboBox的一个事件,就是当点击第一个(省)的时候,传一个省的id过去在去加载市的数据,在加载市的数据之前,应该先清掉之前的数据,这样可以重复利用,我这里的具体实现方式如下:
pdatastore.load(); //加载store() pcombo.on('select', function(comboBox){ //alert(comboBox.getValue()); ccombo.clearValue(); //清理掉上一次的数据 cdatastore.load({params:{temppid: comboBox.getValue()}}); }); ccombo.on('select', function(comboBox){ acombo.clearValue(); adatastore.load({params:{tempcid: comboBox.getValue()}}); }); acombo.on('select', function(comboBox){ alert(pcombo.getValue()+'-'+ccombo.getValue()+'-'+acombo.getValue()); //获取数据后的响应操作 //pcombo.clearValue(); //ccombo.clearValue(); //acombo.clearValue(); });
?到这里就实现了级联下拉列表的js部分,但是要想在页面上显示,把他嵌入到jsp页面中。
?
<body> 省:<input id=pcombo type="text" /> 市:<input id=ccombo type="text" /> 区:<input id=acombo type="text" /> <!-- comboBox必须放在input标签里面 --> </body>
?
到这里页面显示部分就算已经完成了,接下来是后台的实现部分,我这里定义了三个POJO分别是省市区,并且通过ID关联起来,具体代码如下:
public class Province { private String pid; private String pname; //相应的get/set方法 } public class Province { private String pid; private String pname; //相应的get/set方法 } public class Area { private String aid; private String aname; private String cid; //相应的get/set方法 }
?
读取数据库数据的action部分,我这里使用了原始的JDBC代码去读取数据库,方法比较的笨,每次都要开启JDBC的连接和关闭,没有采用工厂的模式,或者框架去实现,也是方便读取数据,这里只是读取简单的数据库表格数据,我个人认为没有必要用到ssh或者ssi之类的,所以我还是选择用JDBC实现,具体代码如下:
package ext.util.comboBox; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import com.opensymphony.xwork2.ActionSupport; /** * 下拉列表级联 * @author lizhenbin * */ public class ComboCascadeAction extends ActionSupport { private List<Province> provinces; private List<City> cities; private List<Area> areas; private String temppid; private String tempcid; private int total; /** * 查找所有的省信息 * @return */ public String findProvinces() throws Exception { Connection conn = null; Statement stmt = null; ResultSet rs = null; List<Province> plist = new ArrayList<Province>(); Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ora10g","weibo","weibo"); stmt = conn.createStatement(); rs = stmt.executeQuery("select * from t_province"); while(rs.next()) { Province temp = new Province(); temp.setPid(rs.getString("PID")); temp.setPname(rs.getString("PNAME")); plist.add(temp); } this.setProvinces(plist); conn.close(); stmt.close(); rs.close(); return "success"; } /** * 通过省Id查询城市 * @return * @throws Exception */ public String findCityByPid() throws Exception { Connection conn = null; Statement stmt = null; ResultSet rs = null; List<City> clist = new ArrayList<City>(); Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ora10g","weibo","weibo"); stmt = conn.createStatement(); rs = stmt.executeQuery("select * from t_city where pid = "+this.temppid+""); while(rs.next()) { City temp = new City(); temp.setCid(rs.getString("CID")); temp.setCname(rs.getString("CNAME")); temp.setPid(rs.getString("PID")); clist.add(temp); } this.setCities(clist); conn.close(); stmt.close(); rs.close(); return "success"; } /** * 通过城市Id查询区域 * @return * @throws Exception */ public String findAreaByCid() throws Exception { Connection conn = null; Statement stmt = null; ResultSet rs = null; List<Area> alist = new ArrayList<Area>(); Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ora10g","weibo","weibo"); stmt = conn.createStatement(); rs = stmt.executeQuery("select * from t_area where cid = "+this.tempcid+""); while(rs.next()) { Area temp = new Area(); temp.setAid(rs.getString("AID")); temp.setAname(rs.getString("ANAME")); temp.setCid(rs.getString("CID")); alist.add(temp); } this.setAreas(alist); conn.close(); stmt.close(); rs.close(); return "success"; } public static void main(String[] agrs) { ComboCascadeAction c = new ComboCascadeAction(); try { c.findProvinces(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public List<Province> getProvinces() { return provinces; } public void setProvinces(List<Province> provinces) { this.provinces = provinces; } public List<City> getCities() { return cities; } public void setCities(List<City> cities) { this.cities = cities; } public List<Area> getAreas() { return areas; } public void setAreas(List<Area> areas) { this.areas = areas; } public String getTemppid() { return temppid; } public void setTemppid(String temppid) { this.temppid = temppid; } public String getTempcid() { return tempcid; } public void setTempcid(String tempcid) { this.tempcid = tempcid; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } }
?
最后就是struts.xml的配置了,我读取数据的时候用到的是JsonReader所以返回的数据应该是Json类型,所以我的配置信息如下:
<package name="weibo_json" namespace="/json" extends="json-default"> <!-- comboBox级联 --> <action name="cascade_*" method="{1}" class="ext.util.comboBox.ComboCascadeAction"> <result type="json"></result> </action> </package>
??
到这里级联下拉列表的后台代码实现部分已经完成,接下来就是在数据库中创建表格,因为主要是演示,所以建立的表格比较的简单:
省表:
-- Create table create table T_PROVINCE ( PID VARCHAR2(20) not null, PNAME VARCHAR2(100) ) tablespace WEIBO_DATA pctfree 10 initrans 1 maxtrans 255 storage ( initial 1M next 1M minextents 1 maxextents unlimited pctincrease 0 ); -- Create/Recreate primary, unique and foreign key constraints alter table T_PROVINCE add constraint PK_T_PROVINCE primary key (PID) using index tablespace WEIBO_DATA pctfree 10 initrans 2 maxtrans 255 storage ( initial 1M next 1M minextents 1 maxextents unlimited pctincrease 0 );
?市表:
-- Create table create table T_CITY ( CID VARCHAR2(20) not null, CNAME VARCHAR2(100) not null, PID VARCHAR2(20) ) tablespace WEIBO_DATA pctfree 10 initrans 1 maxtrans 255 storage ( initial 1M next 1M minextents 1 maxextents unlimited pctincrease 0 ); -- Create/Recreate primary, unique and foreign key constraints alter table T_CITY add constraint PK_T_CITY primary key (CID) using index tablespace WEIBO_DATA pctfree 10 initrans 2 maxtrans 255 storage ( initial 1M next 1M minextents 1 maxextents unlimited pctincrease 0 );
?
区表:
-- Create table create table T_AREA ( AID VARCHAR2(20) not null, ANAME VARCHAR2(20) not null, CID VARCHAR2(20) ) tablespace WEIBO_DATA pctfree 10 initrans 1 maxtrans 255 storage ( initial 1M next 1M minextents 1 maxextents unlimited pctincrease 0 ); -- Create/Recreate primary, unique and foreign key constraints alter table T_AREA add constraint PK_T_AID primary key (AID) using index tablespace WEIBO_DATA pctfree 10 initrans 2 maxtrans 255 storage ( initial 1M next 1M minextents 1 maxextents unlimited pctincrease 0 );
?
到这里全部结束,需要级联的数据,自己在数据库表格中加入即可,我的数据库版本是oracle 10g,你也可以换成其他的比如mysql,换的时候记住要把数据库的连接部分改一下,并且加入相应链接数据库的jar就行,本人能力有限,有什么问题还请多多指教。