这里记录一下如何用ajax实现省市区三级级联。
用到的技术点:前端通过ajax提交请求,后台通过Servlet来响应用户请求,处理之后返回数据。前端用json解析数据显示在页面上。
private List<Province> allProvinces = Arrays.asList(new Province(1,"湖北省"),new Province(2,"湖南省"),new Province(3,"广东省"),new Province(4,"黑龙江省")); private List<City> allCitys = Arrays.asList(new City(1,1,"武汉市"),new City(2,"荆州市"),new City(3,2,"岳阳市"),new City(4,"长沙市"),new City(5,3,"广州市"),new City(6,"深圳市")); private List<Area> allAreas = Arrays.asList(new Area(1,"江夏区"),new Area(2,"沙市区"),new Area(3,"岳阳楼区"),new Area(4,4," 天心区"),new Area(5,5,"天河区"),new Area(6,6,"南山区"),new Area(7,"洪山区"),new Area(8,"荆州区"),new Area(9,"君山区"),new Area(10," 芙蓉区"),new Area(11,"黄埔区"),new Area(12,"罗湖区"));具体就是三个简单的javaBean(代码片段中省略了具体的getter,setter方法和构造方法)。Province.java:
private int id;//省分id private String provinceName;//省分名称City.java:private int id;//城市id private int privinceId;//省分id private String cityName;//城市名称Area.java:private int id;//区id private int cityId;//城市id private String areaName;//区名称
用到的jar包:commons-lang.jar,jackson-all-1.6.2.jar,jackson-core-asl-1.6.2.jar,jackson-mapper-asl-1.6.2.jar,jakarta-oro.jar,jstl-1.2.jar,jstl.jar
<body> <center> 省份: <select id="province"> <option value="">---请选择---</option> <c:forEach var="province" items="${provinceData}"> <option value="${province.id}">${province.provinceName}</option> </c:forEach> </select> 城市: <select id="city"> <option value="">---请选择---</option> </select> 地区: <select id="area"> <option value="">---请选择---</option> </select> </center> </body>main.jsp页面上只有三个下拉列表框,打开该界面之前会先从后台获取省份的信息,城市和地区暂无数据。接下来是获取省份信息的代码,打开首界面test.jsp,然后提交请求到后台获取省份信息。test.jsp页面代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'test.jsp' starting page</title> <script type="text/javascript"> window.onload = function(){ var url = <c:url value="/"></c:url> + 'GetProvinceCityArea?method=getProvince' window.location.href = url; } </script> </head> <body> </body> </html>后端Servlet获取省份信息的代码如下:public void service(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { response.setContentType("text/javascript;charset=UTF-8"); PrintWriter out = response.getWriter(); if (!StringUtils.isBlank(request.getParameter("method"))) { //获取method参数 String method = StringUtils.trim(request.getParameter("method")); if (StringUtils.equals(method,"getProvince")) { this.getProvince(request,response); } else if (StringUtils.equals(method,"getCity")) { this.getCity(request,"getArea")) { this.getArea(request,response); } else { throw new MethodNotFoundException("=======>>未找到指定的方法名"); } } else { throw new NullPointerException("=======>>未指定method参数"); } out.flush(); out.close(); } /** * 获取所有省份信息 * @param request * @param response * @throws ServletException * @throws IOException */ public void getProvince(HttpServletRequest request,IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); request.setAttribute("provinceData",allProvinces); //request作用域中存储数据应该采用转发 request.getRequestDispatcher("getProvinceCity/main.jsp").forward(request,response);//转发 //response.sendRedirect("getProvinceCity/main.jsp");//重定向 out.flush(); out.close(); }这里就不具体解释Servlet的工作原理了。这个转发和重定向解释一下:当使用转发时,JSP容器将使用一个内部的方法来调用目标页面,新的页面继续处理同一个请求,而浏览器将不会知道这个过程。 与之相反,重定向方式的含义是第一个页面通知浏览器发送一个新的页面请求。因为,当你使用重定向时,浏览器中所显示的URL会变成新页面的URL,而当使用转发时,该URL会保持不变。重定向的速度比转发慢,因为浏览器还得发出一个新的请求。同时,由于重定向方式产生了一个新的请求,所以经过一次重定向后,request内的对象将无法使用,request作用域里面存储的值也无法使用。因此,如果我们想要在新的页面中使用request作用域中的值,就要用转发。接下来就是如何通过点击省份来获取对应的城市了,页面代码如下:
$(function(){ $.ajaxSetup ({ cache: false //关闭AJAX相应的缓存 }); //根据省份获取城市信息 $('#province').bind('change',function(){ //清除city下拉框下的下拉项 $('#city option:not(:first)').remove(); //清除area下拉框下的下拉项 $('#area option:not(:first)').remove(); if ($(this).val() == '') { return false; } else { var id = $(this).val(); var url = 'GetProvinceCityArea'; var args = {'method': 'getCity','id': id,'time': new Date()}; //提交请求 $.getJSON(url,args,function(data) { //得到回调数据 if (data.length == 0) { alert('该省份下暂没有录入城市'); return false; } else { for (var i = 0; i < data.length; i++) { var id = data[i].id; var cityName = data[i].cityName; //添加下拉项 $('#city').append('<option value='+ id +'>'+ cityName +'</option>'); } } }); } }); $('#city').bind('change',function(){ //清除area下拉框下的下拉项 $('#area option:not(:first)').remove(); if ($(this).val() == '') { return false; } else { var id = $(this).val(); var url = 'GetProvinceCityArea'; var args = {'method': 'getArea','cityId': id,function(data) { //得到回调数据 if (data.length == 0) { alert('该城市下暂没有录入地区'); return false; } else { for (var i = 0; i < data.length; i++) { var id = data[i].id; var areaName = data[i].areaName; //添加下拉项 $('#area').append('<option value='+ id +'>'+ areaName +'</option>'); } } }); } }); });处理这两个ajax请求的后端代码如下:/** * 获取省份下的城市 * @param request * @param response * @throws ServletException * @throws IOException */ public void getCity(HttpServletRequest request,IOException { response.setContentType("text/javascript;charset=UTF-8"); PrintWriter out = response.getWriter(); ObjectMapper objectMapper = new ObjectMapper(); int provinceId = Integer.parseInt(StringUtils.trim(request.getParameter("id"))); //根据省份id获取城市信息 List<City> citys = new ArrayList<City>(); for (int i = 0; i < allCitys.size(); i++) { if (provinceId == allCitys.get(i).getPrivinceId()) { citys.add(allCitys.get(i)); } } String cityData = objectMapper.writeValueAsString(citys); System.out.println("=======>>cityInfo:" + cityData); response.getWriter().print(cityData); out.flush(); out.close(); } /** * 获取城市下的地区 * @param request * @param response * @throws ServletException * @throws IOException */ public void getArea(HttpServletRequest request,IOException { response.setContentType("text/javascript;charset=UTF-8"); PrintWriter out = response.getWriter(); ObjectMapper objectMapper = new ObjectMapper(); int cityId = Integer.parseInt(StringUtils.trim(request.getParameter("cityId"))); //根据城市id获取地区信息 List<Area> areas = new ArrayList<Area>(); for (int i = 0; i < allAreas.size(); i++) { if (cityId == allAreas.get(i).getCityId()) { areas.add(allAreas.get(i)); } } String areaData = objectMapper.writeValueAsString(areas); System.out.println("=======>>areaInfo:" + areaData); response.getWriter().print(areaData); out.flush(); out.close(); }具体实现过程和代码就是这样了,和省市两级联动的实现过程和原理是一样的,只不过是多了一级的查询。