省市区级联是日常注册网页常用的一个功能,模拟实现如下:
显示界面ProCityArea.jsp
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>省市区级联</title> 8 <script type="text/jscript" src="js/ProCityArea.js" language="javascript"></script> 9 </head> 10 <body> 11 12 <span> 13 <select id="selPro"> 14 </select> 15 </span> 16 17 <span > 18 <select id="selCity"> 19 </select> 20 </span> 21 22 <span > 23 <select id="selArea"> 24 </select> 25 </span> 26 27 </body> 28 </html>
相关的JS代码
1 //JavaScript 2 var xhr; //XMLHttpRequest对象 3 window.onload=function(){ 4 var selPro=$("selPro"); 5 var selCity=$("selCity"); 6 var selArea=$("selArea"); 7 8 //初次加载 9 createXMLObject(); //创建XMLHttpRequest对象 10 doProAjax(false); 11 doCityAjax(selPro.value,false); 12 doAreaAjax(selCity.value,false) 13 14 selPro.onchange=function(){ 15 doCityAjax(this.value,false); 16 doAreaAjax(selCity.value,false); 17 } 18 selCity.onchange=function(){ 19 doAreaAjax(this.value,true); 20 } 21 } 22 23 //创建一个XMLRequest对象 24 var createXMLObject=function(){ 25 if(window.XMLHttpRequest){ 26 xhr=new XMLHttpRequest(); 27 } 28 else{ 29 xhr=new ActiveXObject("Microsoft.XMLHTTP"); 30 } 31 } 32 33 34 var doCityAjax=function(proCode,synFlag){ 35 xhr.open("Get","city.let?proCode="+proCode, synFlag,"admin","admin"); 36 xhr.onreadystatechange=getCity; 37 xhr.send(null); 38 } 39 40 var doProAjax=function(synFlag){ 41 xhr.open("Get","province.let" , synFlag,"admin","admin"); 42 xhr.onreadystatechange=getProvince; 43 xhr.send(null); 44 } 45 46 var doAreaAjax=function(cityCode,synFlag){ 47 xhr.open("Get","area.let?cityCode="+cityCode, synFlag,"admin","admin"); 48 xhr.onreadystatechange=getArea; 49 xhr.send(null); 50 } 51 52 53 //sel:option组件名 tag:自定义标签 54 var getPlaceName=function(sel,tag){ 55 if(xhr.readyState==4 && xhr.status==200){ 56 var xml=xhr.responseXML; 57 sel.innerHTML=""; 58 //解析XML 59 var provinces=xml.getElementsByTagName(tag); 60 61 for(var i=0;i<provinces.length;i++){ 62 var tmp=provinces[i]; 63 //获取相关节点的信息 64 var code=tmp.childNodes[0].textContent; 65 var name=tmp.childNodes[1].textContent; 66 var op=document.createElement("option"); 67 op.setAttribute("value",code); 68 op.innerHTML=name; 69 sel.appendChild(op); 70 } 71 } 72 73 } 74 75 var getProvince=function(){ 76 getPlaceName(selPro,"province"); 77 } 78 79 var getCity=function(){ 80 getPlaceName(selCity,"city"); 81 } 82 83 var getArea=function(){ 84 getPlaceName(selArea,"area"); 85 } 86 87 /*通过Id获取相对应的组件*/ 88 var $=function(id){ 89 return document.getElementById(id); 90 }
com.cnblogs.servlet包下的类:
AreaServlet
1 package com.cnblogs.servlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 import java.util.ArrayList; 6 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 import com.cnblogs.dao.AreaDao; 13 import com.cnblogs.dao.CityDao; 14 import com.cnblogs.vo.Place; 15 16 public class AreaServlet extends HttpServlet { 17 @Override 18 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 19 throws ServletException, IOException { 20 resp.setContentType("text/xml;charset=utf-8"); 21 PrintWriter out= resp.getWriter(); 22 //取出其中的数据 23 String cityCode=req.getParameter("cityCode"); 24 25 //System.out.println(cityCode); 26 ArrayList<Place> arrArea=new AreaDao().getArea(cityCode); 27 28 //拼 xml数据 29 StringBuilder sb=new StringBuilder("<?xml version='1.0' encoding='UTF-8'?>"); 30 sb.append("<areas>"); 31 for(Place tmp:arrArea){ 32 sb.append("<area>"); 33 sb.append("<code>"+tmp.getCode()+"</code>"); 34 sb.append("<name>"+tmp.getName()+"</name>"); 35 sb.append("</area>"); 36 } 37 38 sb.append("</areas>"); 39 //System.out.println(sb.toString()); 40 out.print(sb.toString()); 41 } 42 43 @Override 44 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 45 throws ServletException, IOException { 46 doGet(req, resp); 47 } 48 49 }
CityServlet
1 package com.cnblogs.servlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 import java.util.ArrayList; 6 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 import com.cnblogs.dao.CityDao; 13 import com.cnblogs.dao.ProDao; 14 import com.cnblogs.vo.Place; 15 16 public class CityServlet extends HttpServlet { 17 @Override 18 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 19 throws ServletException, IOException { 20 resp.setContentType("text/xml;charset=utf-8"); 21 PrintWriter out= resp.getWriter(); 22 //取出其中的数据 23 String proCode=req.getParameter("proCode"); 24 ArrayList<Place> arrCity=new CityDao().getCity(proCode); 25 26 27 //拼 xml数据 28 StringBuilder sb=new StringBuilder("<?xml version='1.0' encoding='UTF-8'?>"); 29 sb.append("<citys>"); 30 for(Place tmp:arrCity){ 31 sb.append("<city>"); 32 sb.append("<code>"+tmp.getCode()+"</code>"); 33 sb.append("<name>"+tmp.getName()+"</name>"); 34 sb.append("</city>"); 35 } 36 37 sb.append("</citys>"); 38 //System.out.println(sb.toString()); 39 out.print(sb.toString()); 40 } 41 42 @Override 43 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 44 throws ServletException, IOException { 45 doGet(req, resp); 46 } 47 48 }
ProServlet
1 package com.cnblogs.servlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 import java.util.ArrayList; 6 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 import com.cnblogs.dao.ProDao; 13 import com.cnblogs.vo.Place; 14 15 public class ProServlet extends HttpServlet { 16 17 @Override 18 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 19 throws ServletException, IOException { 20 resp.setContentType("text/xml;charset=utf-8"); 21 PrintWriter out= resp.getWriter(); 22 //取出其中的数据 23 ArrayList<Place> arrPro=new ProDao().getProvince(); 24 25 26 //拼 xml数据 27 StringBuilder sb=new StringBuilder("<?xml version='1.0' encoding='UTF-8'?>"); 28 sb.append("<provinces>"); 29 for(Place tmp:arrPro){ 30 sb.append("<province>"); 31 sb.append("<code>"+tmp.getCode()+"</code>"); 32 sb.append("<name>"+tmp.getName()+"</name>"); 33 sb.append("</province>"); 34 } 35 36 sb.append("</provinces>"); 37 //System.out.println(sb.toString()); 38 out.print(sb.toString()); 39 } 40 41 @Override 42 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 43 throws ServletException, IOException { 44 doGet(req, resp); 45 } 46 47 }
com.cnblogs.vo包下的类
1 package com.cnblogs.vo; 2 3 import java.io.Serializable; 4 5 public class Place implements Serializable{ 6 String code; 7 String name; 8 9 public Place(){} 10 public Place(String code,String name){ 11 this.code=code; 12 this.name=name; 13 } 14 15 16 public String getCode() { 17 return code; 18 } 19 public void setCode(String code) { 20 this.code = code; 21 } 22 public String getName() { 23 return name; 24 } 25 public void setName(String name) { 26 this.name = name; 27 } 28 29 30 }
com.cnblogs.dao下的类
1 package com.cnblogs.dao; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.util.ArrayList; 8 9 import com.cnblogs.comm.DBConnection; 10 import com.cnblogs.vo.Place; 11 12 public class ProDao { 13 //本类主要处理的是省份表的读取 14 public ArrayList<Place> getProvince(){ 15 Connection conn=null; 16 PreparedStatement stmt=null; 17 ResultSet rs=null; 18 19 ArrayList<Place> provinces=null; 20 Place place=null; 21 22 conn=DBConnection.getInstance().getCon(); 23 String sql="select * from province"; 24 try { 25 stmt=conn.prepareStatement(sql); 26 rs=stmt.executeQuery(); 27 28 boolean startFlag=true; 29 while(rs.next()){ 30 if(startFlag){ 31 provinces=new ArrayList<>(); 32 startFlag=false; 33 } 34 String code=rs.getString("code"); 35 String name=rs.getString("name"); 36 place=new Place(code, name); 37 //System.out.println(code+"\t"+name); 38 provinces.add(place); 39 40 } 41 } catch (SQLException e) { 42 e.printStackTrace(); 43 }finally{ 44 DBConnection.close(rs, stmt, conn); 45 } 46 return provinces; 47 } 48 }
1 package com.cnblogs.dao; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.util.ArrayList; 8 9 import com.cnblogs.comm.DBConnection; 10 import com.cnblogs.vo.Place; 11 12 public class CityDao { 13 //本类主要处理的是市的读取 14 public ArrayList<Place> getCity(String proCode){ 15 Connection conn=null; 16 PreparedStatement stmt=null; 17 ResultSet rs=null; 18 19 ArrayList<Place> city=null; 20 Place place=null; 21 22 conn=DBConnection.getInstance().getCon(); 23 String sql="select * from city c where c.provincecode=?"; 24 try { 25 stmt=conn.prepareStatement(sql); 26 stmt.setString(1, proCode); 27 rs=stmt.executeQuery(); 28 29 30 boolean startFlag=true; 31 while(rs.next()){ 32 if(startFlag){ 33 city=new ArrayList<>(); 34 startFlag=false; 35 } 36 String code=rs.getString("code"); 37 String name=rs.getString("name"); 38 place=new Place(code, name); 39 //System.out.println(code+"\t"+name); 40 city.add(place); 41 42 } 43 } catch (SQLException e) { 44 e.printStackTrace(); 45 }finally{ 46 DBConnection.close(rs, stmt, conn); 47 } 48 return city; 49 } 50 }
1 package com.cnblogs.dao; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.util.ArrayList; 8 9 import com.cnblogs.comm.DBConnection; 10 import com.cnblogs.vo.Place; 11 12 public class AreaDao { 13 //本类主要处理的是区的读取 14 public ArrayList<Place> getArea(String cityCode){ 15 Connection conn=null; 16 PreparedStatement stmt=null; 17 ResultSet rs=null; 18 19 ArrayList<Place> area=null; 20 Place place=null; 21 22 conn=DBConnection.getInstance().getCon(); 23 String sql="select * from area a where a.citycode=?"; 24 try { 25 stmt=conn.prepareStatement(sql); 26 stmt.setString(1, cityCode); 27 rs=stmt.executeQuery(); 28 29 30 boolean startFlag=true; 31 while(rs.next()){ 32 if(startFlag){ 33 area=new ArrayList<>(); 34 startFlag=false; 35 } 36 String code=rs.getString("code"); 37 String name=rs.getString("name"); 38 place=new Place(code, name); 39 //System.out.println(code+"\t"+name); 40 area.add(place); 41 42 } 43 } catch (SQLException e) { 44 e.printStackTrace(); 45 }finally{ 46 DBConnection.close(rs, stmt, conn); 47 } 48 return area; 49 } 50 51 }
数据库脚本
注意:region-oracle(修改版)是本例使用的数据库脚本
以上代码基本可以实现省市区的级联,其中最关键的技术Ajax的异步与同步的运用。
如xx省的改变,必须同时改变市以及区的数据,
selPro.onchange=function(){ 15 doCityAjax(this.value,false); 16 doAreaAjax(selCity.value,false); 17 }
此处必须使用同步的方式,否则数据无法同时修改,还有本例无法再IE中运行,关键原因是IE无法解析XML=xhr.responseXML;暂时无法知晓原因
2013-11-05排除兼容性问题
上面谈到xhr.responseXML在IE中出现undefined问题
解决方法为:
var code=tmp.childNodes[0].firstChild.nodeValue;
var name=tmp.childNodes[1].firstChild.nodeValue;
2013-11-06JSON技术处理
其中主要修改的内容为:
如AreaServlet类中部分代码修改如下:
1 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 2 throws ServletException, IOException { 3 resp.setContentType("text/html;charset=utf-8"); 4 PrintWriter out= resp.getWriter(); 5 //取出其中的数据 6 String cityCode=req.getParameter("cityCode"); 7 8 //System.out.println(cityCode); 9 ArrayList<Place> arrArea=new AreaDao().getArea(cityCode); 10 11 //拼 xml数据 12 StringBuilder sb=new StringBuilder(); 13 sb.append("["); 14 for(Place tmp:arrArea){ 15 sb.append("{"); 16 sb.append("code:\""+tmp.getCode()+"\","); 17 sb.append("name:\""+tmp.getName()+"\""); 18 sb.append("},"); 19 } 20 sb.deleteCharAt(sb.length()-1); 21 sb.append("]"); 22 //System.out.println(sb.toString()); 23 out.print(sb.toString()); 24 }
ProCityArea.js文件中getArea()方法调用以下方法
1 var getJSON=function(sel){ 2 if(xhr.readyState==4 && xhr.status==200){ 3 var jsonStr=xhr.responseText; 4 5 sel.innerHTML=""; 6 var area=eval("("+jsonStr+")"); 7 8 for(var i=0;i<area.length;i++){ 9 var tmp=area[i]; 10 //获取相关节点的信息 11 var code=tmp.code; 12 var name=tmp.name; 13 var op=document.createElement("option"); 14 op.setAttribute("value",code); 15 op.innerHTML=name; 16 sel.appendChild(op); 17 } 18 19 } 20 }
JSON可以完美兼容浏览器而且其数据量小