Ajax进阶篇(四)——使用jQuery实现省市联动

我们在购物的时候,常常需要我们来选择自己的收货地址,先选择省份,再选择城市…,有没有发现:当我们选择完省份的时候,出现的城市全部都是根据省份来给我们选择的。这是怎么做到的呢?其实就是通过Ajax来完成的。使用Ajax技术让我们的网页看起来非常“智能”,会根据省份来给出对应的城市信息。
Ajax进阶篇(四)——使用jQuery实现省市联动_第1张图片

搭建环境

新建一个动态Web项目,比如ProvinceCity。接着导入该项目所须的jar包:

  • mysql-connector-java-5.1.38-bin.jar:MySQL数据库驱动包;
  • c3p0-0.9.1.2.jar:Java配置C3P0数据库连接池使用的包;
  • commons-dbutils-1.4.jar:Apache组织提供的一个开源JDBC工具类库;
  • jstl.jar和standard.jar:JSTL标签库和EL表达式依赖包。

Ajax进阶篇(四)——使用jQuery实现省市联动_第2张图片
然后在WebContent根目录下创建一个city.jsp页面,其内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body>
	省份:
	<select name="province" id="province">
		<option value="">请选择option>
		<option value="1">广东省option>
		<option value="2">湖南省option>
		<option value="3">湖北省option>
		<option value="4">四川省option>
	select>
	城市:
	<select name="city" id="city">
		<option value="">请选择option>
	select>
body>
html>

注意:这里省份的数据直接写死在页面中,而城市列表信息是要从数据库中读取的。还有,千万不要忘了在项目中导入jQuery的支持,所以应在WebContent根目录下新建一个js目录,并在该目录下导入jQuery的支持,如下:
Ajax进阶篇(四)——使用jQuery实现省市联动_第3张图片
最后,需要在MySQL数据库中新建一个baidu数据库,并在该数据库中新建一个city表,表中记录类似如下:
Ajax进阶篇(四)——使用jQuery实现省市联动_第4张图片
由于建库建表语句非常简单,所以这里我就省略不写了。

使用jQuery实现省市联动(XML版)

我们知道Ajax与服务器之间的交互常用的传输载体格式有三种:

  • HTML
  • XML
  • JSON

由于省份与城市是有层级关系的,因此我们只能用XML或者JSON。我们这里首先就用XML来进行,后面会使用JSON,来看看他俩有什么不同的地方。开发环境搭建好了之后,接下来我们就要编写程序,实现省市联动这个需求了。

开发domain层

在com.meimeixia.domain包中创建一个封装城市信息的实体JavaBean。

package com.meimeixia.domain;

public class CityBean {
	
	private int id;
	private int pid;
	private String cname;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getPid() {
		return pid;
	}
	public void setPid(int pid) {
		this.pid = pid;
	}
	public String getCname() {
		return cname;
	}
	public void setCname(String cname) {
		this.cname = cname;
	}
	
}

开发数据访问层(dao、dao.impl)

为了提升程序的数据库访问性能,我们通常应在项目开发中使用C3P0数据源。所以应在类目录下加入C3P0的配置文件:c3p0-config.xml。
Ajax进阶篇(四)——使用jQuery实现省市联动_第5张图片
c3p0-config.xml配置文件的内容如下:


<c3p0-config>
	
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driverproperty>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/baiduproperty>
		<property name="user">rootproperty>
		<property name="password">liayunproperty>

		<property name="initialPoolSize">10property>
		<property name="maxIdleTime">30property>
		<property name="maxPoolSize">100property>
		<property name="minPoolSize">10property>
		<property name="maxStatements">200property>
	default-config>

	<named-config name="oracle">
		<property name="acquireIncrement">50property>
		<property name="initialPoolSize">100property>
		<property name="minPoolSize">50property>
		<property name="maxPoolSize">1000property>

		
		<property name="maxStatements">0property>
		<property name="maxStatementsPerConnection">5property>

		
		<user-overrides user="master-of-the-universe">
			<property name="acquireIncrement">1property>
			<property name="initialPoolSize">1property>
			<property name="minPoolSize">1property>
			<property name="maxPoolSize">5property>
			<property name="maxStatementsPerConnection">50property>
		user-overrides>
	named-config>
c3p0-config>

也是为了简化JDBC的开发,我们使用Apache组织提供的一个开源JDBC工具类库——commons-dbutils-1.4.jar。然后在com.meimeixia.util包下创建一个工具类——JDBCUtil02.java,用于读取C3P0的xml配置文件创建数据源,该工具类的具体代码如下:

package com.meimeixia.util;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JDBCUtil02 {
	static ComboPooledDataSource dataSource = null;
	
	static {
		dataSource = new ComboPooledDataSource();
	}
	
	public static DataSource getDataSource() {
		return dataSource;
	}
	
	/**
	 * 获取连接对象
	 * @return
	 * @throws SQLException 
	 */
	public static Connection getConn() throws SQLException{
		return dataSource.getConnection();
	}
	
	/**
	 * 释放资源
	 * @param conn
	 * @param st
	 * @param rs
	 */
	public static void release(Connection conn , Statement st , ResultSet rs){
		closeRs(rs);
		closeSt(st);
		closeConn(conn);
	}
	
	public static void release(Connection conn , Statement st){
		closeSt(st);
		closeConn(conn);
	}
	
	private static void closeRs(ResultSet rs){
		try {
			if(rs != null){
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			rs = null;
		}
	}
	
	private static void closeSt(Statement st){
		try {
			if(st != null){
				st.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			st = null;
		}
	}
	
	private static void closeConn(Connection conn){
		try {
			if(conn != null){
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			conn = null;
		}
	}
}

准备好以上这些工作之后,我们正式步入开发数据库访问层的阶段。在com.meimeixia.dao包下创建一个CityDao接口,该接口的具体代码如下:

package com.meimeixia.dao;

import java.sql.SQLException;
import java.util.List;

import com.meimeixia.domain.CityBean;

public interface CityDao {
	
	List<CityBean> findCity(int pid) throws SQLException;
	
}

紧接着在com.meimeixia.dao.impl包中新建CityDao接口的实现类,即CityDaoImpl类,该实现类的代码如下:

package com.meimeixia.dao.impl;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import com.meimeixia.dao.CityDao;
import com.meimeixia.domain.CityBean;
import com.meimeixia.util.JDBCUtil02;

public class CityDaoImpl implements CityDao {

	@Override
	public List<CityBean> findCity(int pid) throws SQLException {
		QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
		String sql = "select * from city where pid = ?";
		return runner.query(sql, new BeanListHandler<CityBean>(CityBean.class), pid);
	}

}

开发web层

得到前台带过来的数据(这里是省份ID),服务器端判断该数据是什么,返回对应的XML文件,内容类似下面:

<list>
	<city>
		<id>1id>
		<pid>1pid>
		<cname>深圳cname>
	city>
	<city>
		<id>2id>
		<pid>1pid>
		<cname>东莞cname>
	city>
	<city>
		<id>3id>
		<pid>1pid>
		<cname>广州cname>
	city>
	<city>
		<id>4id>
		<pid>1pid>
		<cname>惠州cname>
	city>
list>

试想服务器端查询出某个省份下的所有城市,想必是一个List集合,而要返回给前台的是一个XML文件,那么怎么把一个Bean对象转换成一个XML文件呢?这里就不得不简单学习一下xStream的使用了。
首先,在项目中导入xStream所须jar包,如下:
Ajax进阶篇(四)——使用jQuery实现省市联动_第6张图片
然后,简单介绍一下xStream的API,试着将一个Bean对象转换成一个XML文件。
Ajax进阶篇(四)——使用jQuery实现省市联动_第7张图片
那么如何给标签设置别名呢?可调用xStream中的alias方法设置别名。
Ajax进阶篇(四)——使用jQuery实现省市联动_第8张图片
如果我们想把id做成属性,就像下面这样子,那么该怎么做呢?
Ajax进阶篇(四)——使用jQuery实现省市联动_第9张图片
可调用xStream中的useAttributeFor方法将id做成属性。
Ajax进阶篇(四)——使用jQuery实现省市联动_第10张图片
我们已经会将一个Bean对象转换成一个XML文件了,那么把一个XML文件转换成一个Bean对象(逆向)又该怎么做呢?这里给出核心代码:
Ajax进阶篇(四)——使用jQuery实现省市联动_第11张图片
xStream的简单使用,我们已经会了,那么就可以完整地编写出服务器端的Servlet了,在com.meimeixia.servlet中新建一个CityServlet,其内容如下:

package com.meimeixia.servlet;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.meimeixia.dao.CityDao;
import com.meimeixia.dao.impl.CityDaoImpl;
import com.meimeixia.domain.CityBean;
import com.thoughtworks.xstream.XStream;

public class CityServlet extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			//1. 获取参数
			int pid = Integer.parseInt(request.getParameter("pid"));
			
			//2. 找出所有的城市
			CityDao dao = new CityDaoImpl();
			List<CityBean> list = dao.findCity(pid);
			
			//3. 返回数据。手动拼一个xml文件,XStream转换bean对象成xml
			XStream xStream = new XStream();
			
			//想把id做出属性
			//xStream.useAttributeFor(CityBean.class, "id");
			
			//设置别名
			xStream.alias("city", CityBean.class);
			
			//转换一个对象成xml字符串
			String xml = xStream.toXML(list);
			//System.out.println(xml);
			
			//返回数据
			response.setContentType("text/xml;charset=UTF-8");
			response.getWriter().write(xml);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

后台我们已经分析完了,接着来分析前台。当用户选择了某个省份之后,就使用Ajax与服务器进行交互,那么在选择省份的时候就出现对应的城市信息。分析步骤如下:

  1. 监听省份下拉框值变化事件;
  2. 只要省份下拉框值变化了,就与服务器进行交互;
  3. 得到服务器返回的值,解析XML;
  4. 使用DOM把数据写到城市下拉框列表中。

这样,city.jsp页面的内容就要修改为:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
<script type="text/javascript" src="js/jquery-1.11.3.min.js">script>
<script type="text/javascript" src="js/city.js">script>
head>
<body>
	省份:
	<select name="province" id="province">
		<option value="">请选择option>
		<option value="1">广东省option>
		<option value="2">湖南省option>
		<option value="3">湖北省option>
		<option value="4">四川省option>
	select>
	城市:
	<select name="city" id="city">
		<option value="">请选择option>
	select>
body>
html>

其中,js目录下的city.js文件的内容如下:

$(function() {
	//1. 找到省份的元素
	$("#province").change(function() {
		//2. 一旦里面的值发生了改变,那么就去请求该省份下面的城市数据
		//$("#province").val();
		var pid = $(this).val();
		
		/*
			
				
					1
					1
					深圳
				
				
					2
					1
					东莞
				
				
					3
					1
					广州
				
				
					4
					1
					惠州
				
			
		*/
		$.post("CityServlet", {pid:pid}, function(data, status) {
			//alert("回来数据了:" + data);
			
			//先清空以前的值
			$("#city").html("");
			
			//遍历:
			//从data数据里面找出所有的city元素,然后遍历所有的city元素,
			//遍历到一个city元素,就执行一次function方法
			$(data).find("city").each(function() {
				//遍历出来的每一个city元素,取它的孩子(也即id和cname元素)
				var id = $(this).children("id").text();
				var cname = $(this).children("cname").text();
				//alert("id = " + id + ", cname = " + cname);
				
				//append:追加
				$("#city").append(" + cname + "");
			});
		});
	});
});

最后,在Google Chrome浏览器中测试的效果如下:
Ajax进阶篇(四)——使用jQuery实现省市联动_第12张图片

XML方式总结

监听下拉框的变化,如果变化了,那么就使用异步操作去访问服务器,得到对应的数据返回给异步对象。异步对象解析服务器带过来的数据,使用DOM编程把数据动态添加到页面上。在编写代码的过程中,我们可能要注意以下几点:

  • 在Servlet上记得要指定返回的是XML的数据;
  • 由于每次append到下拉框都会连续append,因此在响应事件的时候,把下拉框清零;
  • 从data数据里面找出所有的city元素,然后遍历所有的city元素,遍历出来的每一个city元素,取它的孩子(也即id和cname元素),可以通过child()的方式获取。

使用jQuery实现省市联动(JSON版)

前面我们已经使用过了XML作为数据载体在Ajax中与服务器进行交互。这次我们使用JSON作为数据载体在Ajax与服务器之间交互。

开发domain层

同上。

开发数据访问层(dao、dao.impl)

同上。

开发web层

得到前台发送过来的数据(这里是省份ID),判断具体的数据是什么,给出对应的数据,然后使用工具把数据封装成JSON,返回给浏览器。JSON数据的内容类似下面这样:

[
    {
        "cname": "深圳",
        "id": 1,
        "pid": 1
    },
    {
        "cname": "东莞",
        "id": 2,
        "pid": 1
    }
    , 
    ...
]

试想服务器端查询出某个省份下的所有城市,想必是一个List集合,而要返回给前台的是一个JSON格式的数据,那么怎么把一个Bean对象转换成一个JSON格式的数据呢?首先,我们要在项目中导入JSON依赖的必要jar包,如下:
Ajax进阶篇(四)——使用jQuery实现省市联动_第13张图片
这里,必须要介绍两个常用类了:

  • JSONArray:该类能将一个Bean对象转换成一个JSON数组,例如,

    [
        {
            "cname": "深圳",
            "id": 1,
            "pid": 1
        },
        {
            "cname": "东莞",
            "id": 2,
            "pid": 1
        }
        , 
        ...
    ]
    

    其核心代码为:

    JSONArray jsonArray = JSONArray.fromObject(list);
    String json = jsonArray.toString();
    System.out.println("json = " + json);
    
  • JSONObject:该类能将一个Bean对象转换成一个简单的JSON对象,例如,

    {name:"zhangsan", age:18}
    

现在我们就可以完整地编写出服务器端的Servlet了,在com.meimeixia.servlet中新建一个CityServlet02,其内容如下:

package com.meimeixia.servlet;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.meimeixia.dao.CityDao;
import com.meimeixia.dao.impl.CityDaoImpl;
import com.meimeixia.domain.CityBean;

import net.sf.json.JSONArray;

public class CityServlet02 extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			//1. 获取参数
			int pid = Integer.parseInt(request.getParameter("pid"));
			
			//2. 找出所有的城市
			CityDao dao = new CityDaoImpl();
			List<CityBean> list = dao.findCity(pid);
			
			//3. 把List集合转成一个JSON数据
			//JSONArray ---> 变成数组([])或者集合
			//JSONObject ---> 变成简单的数据,{name:"zhangsan", age:18}
			
			JSONArray jsonArray = JSONArray.fromObject(list);
			String json = jsonArray.toString();
			//System.out.println("json = " + json);
			
			response.setContentType("text/html;charset=UTF-8");
			response.getWriter().write(json);
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

后台我们已经分析完了,接着来分析前台。当用户选择了某个省份之后,就使用Ajax与服务器进行交互,那么在选择省份的时候就出现对应的城市信息。分析步骤如下:

  1. 监听省份下拉框的变动;
  2. 得到服务器返回的JSON数据,并进行解析;
  3. 使用DOM编程把数据填充到对应的下拉框上。

这样,city.jsp页面的内容就要修改为:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
<script type="text/javascript" src="js/jquery-1.11.3.min.js">script>

<script type="text/javascript" src="js/city_json.js">script>
head>
<body>
	省份:
	<select name="province" id="province">
		<option value="">请选择option>
		<option value="1">广东省option>
		<option value="2">湖南省option>
		<option value="3">湖北省option>
		<option value="4">四川省option>
	select>
	城市:
	<select name="city" id="city">
		<option value="">请选择option>
	select>
body>
html>

其中,js目录下的city_json.js文件的内容如下:

$(function() {
	//1. 找到省份的元素
	$("#province").change(function() {
		//2. 一旦里面的值发生了改变,那么就去请求该省份下面的城市数据
		//$("#province").val();
		var pid = $(this).val();
		
		/*
		[
		    {
		        "cname": "深圳",
		        "id": 1,
		        "pid": 1
		    },
		    {
		        "cname": "东莞",
		        "id": 2,
		        "pid": 1
		    }
		    , 
		    ...
		]
		*/
		$.post("CityServlet02", {pid:pid}, function(data, status) {
			//先清空以前的值
			$("#city").html("");
			
			//再遍历,进行追加
			$(data).each(function(index, c) {
				//alert(c.cname);
				
				$("#city").append(" + c.cname + "");
			});
			
		}, "json");
	});
});

JSON方式总结

这次使用的是JSON作为数据载体与服务器进行交互,和XML本质上是没有区别的。只不过JSON是更加轻量级文本数据,JavaScript能够方便地获取返回的数据。

你可能感兴趣的:(▬▬▬【Ajax学习】)