今天学习了Ajax技术,刚刚做了一个省份-城市联动的Ajax应用示例。可能很多人都已经写过了,也是一个比较简单的例子,在这里分享出来大家共同学习交流一下。希望能给到那些像我一样的菜鸟程序员参考一点帮助吧!
效果截图:
省份-城市联动就是当你在省份下拉列表框选择一个省份的时候,旁边的城市下拉列表框就会动态地生成该省份对应的城市列表。如:省份是广东,则城市的下拉框对应显示广州、茂名、梅州等城市;省份是北京,城市的下拉列表框则显示海淀、朝阳等城市。因为我本人主要从事JavaEE的相关开发,因此这个小应用示例也就写专业一点啦!使用model2的两层架构。因为是一个小应用示例,因此没有跟数据库打交道,数据就都保存到内存中。
好了,我讲的废话太多了,下面开始叙述省份-城市联动的开发过程。
实施步骤:
- 编写后台service层。在三层架构中,层与层之间使用接口连接,因此要编写service接口。
- 编写后台web层的控制器servlet(省份的控制器和城市的控制器),主要负责加载后台省份和城市的数据,并将其传输到前台页面。
- 编写前台html静态页面,负责给用户显示数据。
- 编写javascript脚本程序,处理用户选择省份的请求操作。
整个应用的流程图:
(一)service层的接口代码
package cn.itcast.ajax.service;
import java.util.List;
public interface ProvinceCityService {
/**
* 返回省份数据集合
* @return
*/
List<String> loadProvince();
/**
* 根据省份返回城市的集合
* @param province
* @return
*/
List<String> loadCity(String province);
}
实现接口中定义的功能
package cn.itcast.ajax.service.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import cn.itcast.ajax.service.ProvinceCityService;
public class ProvinceCityServiceImpl implements ProvinceCityService {
/*
* 因为是一个省份与城市下拉的ajax小应用实例,因此不与数据库交道了,使用map存储数据 (non-Javadoc)
*
* @see cn.itcast.ajax.service.ProvinceService#loadProvince()
*/
private Map<String, List<String>> provinceMap = new HashMap<String, List<String>>();
String[] gdCity = new String[] { "广州", "汕头", "梅州", "茂名" };
String[] bjCity = new String[] { "海淀", "朝阳", "中关村" };
public ProvinceCityServiceImpl() {
provinceMap.put("广东", Arrays.asList(gdCity));
provinceMap.put("北京", Arrays.asList(bjCity));
}
@Override
public List<String> loadProvince() {
List<String> provinces = new ArrayList<String>();
Set<String> keySet = provinceMap.keySet();
for (Iterator<String> iterator = keySet.iterator(); iterator.hasNext();) {
String province = iterator.next();
provinces.add(province);
}
return provinces;
}
@Override
public List<String> loadCity(String province) {
return provinceMap.get(province);
}
}
(二)控制层Servlet代码
因为需要对省份和城市分开不同处理,所以使用ProvinceServlet和CityServlet两个servlet控制器
ProvinceServlet:
package cn.itcast.ajax.servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.ajax.service.ProvinceCityService;
import cn.itcast.ajax.service.impl.ProvinceCityServiceImpl;
/**
* Servlet implementation class ProvinceServlet
*/
public class ProvinceServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private ProvinceCityService provinceService = new ProvinceCityServiceImpl();
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
List<String> provinces = provinceService.loadProvince();
StringBuffer sb = new StringBuffer();
sb.append("[");
for (int i =0;i<provinces.size();i++) {
String province = provinces.get(i);
sb.append("\"").append(province).append("\"");
// 如果i的值小于list的长度的时候就添加一个逗号,确保最后一个不会添加多一个逗号
if (i < provinces.size() - 1) {
sb.append(",");
}
}
sb.append("]");
response.setHeader("Content-Type", "text/html; charset=UTF-8");
response.getWriter().println(sb.toString());
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
public void testData() {
List<String> provinces = provinceService.loadProvince();
StringBuffer sb = new StringBuffer();
sb.append("[");
for (int i =0;i<provinces.size();i++) {
String province = provinces.get(i);
sb.append("\"").append(province);
// 如果i的值小于list的长度的时候就添加一个逗号,确保最后一个不会添加多一个逗号
if (i < provinces.size() - 1) {
sb.append(",");
}
}
sb.append("]");
System.out.println(sb.toString());
}
}
CityServlet:
package cn.itcast.ajax.servlet;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.ajax.service.ProvinceCityService;
import cn.itcast.ajax.service.impl.ProvinceCityServiceImpl;
/**
* Servlet implementation class CityServlet
*/
public class CityServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private ProvinceCityService cityService = new ProvinceCityServiceImpl();
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String province = request.getParameter("province");
List<String> citys = cityService.loadCity(province);
StringBuffer sb = new StringBuffer("[");
for (int i = 0; i < citys.size(); i++) {
sb.append("\"").append(citys.get(i)).append("\"");
if (i < citys.size() - 1) {
sb.append(",");
}
}
sb.append("]");
response.setHeader("Content-Type", "text/html; charset=UTF-8");
response.getWriter().println(sb.toString());
response.getWriter().close();
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
(三)前台html静态页面province_city.html
这里要注意一点,省份的数据需要首先加载出来,添加到省份的下拉列表框中,因此在这个页面载入的时候就必须从后台加载数据出来。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>省份-城市下拉联动</title>
<script type="text/javascript" src="province_city.js"></script>
</head>
<body>
请选择省份:<select id="province" οnchange="provinceChange()"></select>
请选择城市:<select id="city"></select>
</body>
</html>
(四)javascript脚本程序province_city.js
// 初始化XMLHttpRequest对象
function createXmlHttpRequest() {
var xmlhttp = null;
try {
// Firefox, Opera 8.0+, Safari
xmlhttp = new XMLHttpRequest();
} catch (e) {// IE7.0以下的浏览器以ActiveX组件的方式来创建XMLHttpRequest对象
var MSXML = [ 'MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP' ];
for ( var i = 0; i < MSXML.length; i++) {
try {
xmlhttp = new ActiveXObject(MSXML[i]);
break;
} catch (e) {
}
}
}
// 返回对象
return xmlhttp;
}
window.onload = function() {
loadProvinces();
};
// 加载省份数据
function loadProvinces() {
var province = document.getElementById("province");
//alert("sdhgjf");
// 创建XMLHttpRequest对象
var xhr = createXmlHttpRequest();
// 发送请求
xhr.open("get", "ProvinceServlet", true);
xhr.send(null);
// 接收服务器端传递回来的数据
xhr.onreadystatechange = function() {
// 判断数据是否处理完全
if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
var provinces = eval("(" + xhr.responseText + ")");
//alert(provinces);
// 处理返回来的字符串
var s = "<option>请选择</option>";
for ( var i = 0; i < provinces.length; i++) {
s+="<option>"+provinces[i]+"</option>";
}
province.innerHTML = s;
}
};
}
// 省份选择发生改变的时候的处理函数
function provinceChange() {
// 获取当前选中的省份
var provinces = document.getElementById("province");
var province = provinces.options[provinces.selectedIndex].value;
var city = document.getElementById("city");
//alert(province);
var xhr = createXmlHttpRequest();
xhr.open("post", "CityServlet", true);
// 以post方式发送请求的时候需要设置请求的方式
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("province="+province);
// 处理服务器端返回来的数据
xhr.onreadystatechange = function() {
// 判断数据是否处理完全
if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
var citys = eval("(" + xhr.responseText + ")");
//alert(provinces);
// 处理返回来的字符串
var s = "<option>--</option>";// 创建一个option子元素
for ( var i = 0; i < citys.length; i++) {// 将返回来的城市数据添加到option元素中
s+="<option>"+citys[i]+"</option>";
}
city.innerHTML = s;
}
};
}
示例源代码下载
因为这个小应用纯粹用于学习总结,因此写了比较多的注释,但是总体还算比较易于阅读的。