先看下效果图:
项目结构:
1.准备数据库
表结构:
我把数据库、jquery和项目所用的jar包上传到了百度云盘,如果有需要可以下载。
链接:https://pan.baidu.com/s/1VijPG7LPeJoOHCa2mZsrww
提取码:fz86
先分析下数据库里面的数据,分析省份、城市、地区之间的联系。
分析ajax执行过程:
ajax向服务器发送请求,Servlet接收ajax发来的请求,获取ajax传递的数据。服务器内部调用dao类,获取数据库中的数据,此时数据是Java对象或Java数组格式的。然后将数据转为json格式的数据,返回给ajax。ajax就在success函数中将响应回来的json数据进行解析,然后输出到jsp页面。
2.编写前端页面
index.jsp:
<body>
<table>
<tr>
<td>
<%--省份的parentid为0,故value不能取0,否则当你选择“请选择省份”时,城市就显示省份--%>
<select id="province">
<option value="-1">--请选择省份--</option>
</select>
</td>
<td>
<select id="city">
<option value="-1">--请选择城市--</option>
</select>
</td>
<td>
<select id="area">
<option value="-1">--请选择地区--</option>
</select>
</td>
</tr>
</table>
</body>
加点css样式:
<style>
select{
width:110px;
height: 25px;
}
</style>
3.编写实体类
Area.java:
public class Area {
private Integer baseAreaId;
private String name;
private Integer parentId;
private Integer viewOrder;
public Area() {
}
public Area(Integer baseAreaId, String name, Integer parentId, Integer viewOrder) {
this.baseAreaId = baseAreaId;
this.name = name;
this.parentId = parentId;
this.viewOrder = viewOrder;
}
public Integer getBaseAreaId() {
return baseAreaId;
}
public void setBaseAreaId(Integer baseAreaId) {
this.baseAreaId = baseAreaId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
public Integer getViewOrder() {
return viewOrder;
}
public void setViewOrder(Integer viewOrder) {
this.viewOrder = viewOrder;
}
}
4.编写dao接口并实现接口
AreaDao.java:
public interface AreaDao {
/**
* 查询所有省份信息
* @return 省份信息
*/
public List<Area> findProvinceList();
/**
* 查询所有城市信息
* @param parentId
* @return 城市信息
*/
public List<Area> findCityList(Integer parentId);
/**
* 查询地区信息(点击省份就出现的地区)
* @param parentId
* @return
*/
public List<Area> findAreaList(Integer parentId);
}
AreaDaoImpl.java:
package com.dao.impl;
import com.bean.Area;
import com.dao.AreaDao;
import com.util.DruidUtil;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class AreaDaoImpl extends DruidUtil implements AreaDao {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
/**
* 查询所有省份信息
*
* @return 省份信息
*/
@Override
public List<Area> findProvinceList() {
List<Area> provinceList = new ArrayList<>();
try {
conn = getConnection();
ps = conn.prepareStatement("select base_areaid,name,parentid,vieworder from area where parentid=0 order by base_areaid");
rs = ps.executeQuery();
while(rs.next()){
Area province = new Area();
province.setBaseAreaId(rs.getInt("base_areaid"));
province.setName(rs.getString("name"));
province.setParentId(rs.getInt("parentid"));
province.setViewOrder(rs.getInt("vieworder"));
provinceList.add(province);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(conn,ps,rs);
}
return provinceList;
}
/**
* 查询所有城市信息
*
* @return 城市信息
*/
@Override
public List<Area> findCityList(Integer parentId) {
List<Area> cityList = new ArrayList<>();
try {
conn = getConnection();
ps = conn.prepareStatement("select base_areaid,name,parentid,vieworder from area where parentid=? order by base_areaid");
ps.setInt(1,parentId);
rs = ps.executeQuery();
while(rs.next()){
Area city = new Area();
city.setBaseAreaId(rs.getInt("base_areaid"));
city.setName(rs.getString("name"));
city.setParentId(rs.getInt("parentid"));
city.setViewOrder(rs.getInt("vieworder"));
cityList.add(city);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(conn,ps,rs);
}
return cityList;
}
/**
* 查询地区信息(点击省份就出现的地区)
* 省份的base_areaid=城市的parentid,通过选择省份,获取到省份的base_areaid,将它赋给城市的parentid,然后再选择城市的vieworder=1的地区
* @param parentId
* @return
*/
@Override
public List<Area> findAreaList(Integer parentId) {
List<Area> areaList = new ArrayList<>();
try {
conn = getConnection();
ps = conn.prepareStatement("select diqu.base_areaid,diqu.name,diqu.parentid,diqu.vieworder from area as city,area as diqu where city.parentid=? and city.base_areaid=diqu.parentid and city.vieworder=1");
ps.setInt(1,parentId);
rs = ps.executeQuery();
while(rs.next()){
Area area = new Area();
area.setBaseAreaId(rs.getInt("base_areaid"));
area.setName(rs.getString("name"));
area.setParentId(rs.getInt("parentid"));
area.setViewOrder(rs.getInt("vieworder"));
areaList.add(area);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(conn,ps,rs);
}
return areaList;
}
}
注意:
由于点击省份获取城市数据 和 点击城市获取地区数据的实现方式一模一样,所以findCityList(Integer parentId)该方法可以用于城市和地区,
而findAreaList(Integer parentId)用于点击省份时城市和地区一并出现的情况。
分析SQL语句
select diqu.base_areaid,diqu.name,diqu.parentid,diqu.vieworder
from area as city,area as diqu
where city.parentid=?
and city.base_areaid=diqu.parentid
and city.vieworder=1
省份的base_areaid=城市的parentid,通过选择省份,获取到省份的base_areaid,将它赋给城市的parentid,然后再选择城市的vieworder=1的地区。
也就是说点击省份就可以获取正在显示的城市的各个地区。
5.编写ajax请求
<script type="text/javascript" src="js/jquery-3.5.0.min.js"></script>
<script type="text/javascript">
$(function () {
//dom对象加载成功后发起ajax
loadProvince();
$("#province").change(function () {
loadCity();
})
$("#city").change(function () {
loadArea();
})
})
//加载省下拉列表
function loadProvince(){
$.ajax({
url:"/queryProvince",
dataType:"json",
success:function (data) {
$("#province:gt(0)").empty();
$.each(data,function (index,element) {
$("#province").append("<option value='"+element.baseAreaId+"'>"+element.name+"</option>");
})
}
})
}
//加载城市的下拉列表(点击省份,获取城市和地区的数据)
function loadCity(){
//获取到base_areaid的值
var provinceId = $("#province>option:selected").val();
//ajax以post方式发起请求,获取城市的数据
$.post("/queryCity",{parentid:provinceId},function (data) {
$("#city").empty();
//当用户选到"请选择省份",城市变为"请选择城市"
if(provinceId == -1){
$("#city").append("<option value='-1'>"+"--请选择城市--"+"</option>");
}
$.each(data,function (index,element) {
$("#city").append("<option value='"+element.baseAreaId+"'>"+element.name+"</option>");
})
},"json");
//ajax以post方式发起请求,获取地区的数据
$.post("/queryArea",{parentid:provinceId},function (data) {
$("#area").empty();
if(provinceId == -1){
$("#area").append("<option value='-1'>"+"--请选择地区--"+"</option>");
}
$.each(data,function (index,element) {
$("#area").append("<option>"+element.name+"</option>");
})
},"json");
}
//加载地区的下列列表(和请求城市数据方式一模一样,就直接使用city的servlet路径)
function loadArea() {
var cityId = $("#city>option:selected").val();
$.post("/queryCity",{parentid:cityId},function (data) {
$("#area").empty();
$.each(data,function (index,element) {
$("#area").append("<option value='"+element.baseAreaId+"'>"+element.name+"</option>");
})
},"json");
}
</script>
6.编写Servlet
FindProvinceServlet.java(返回省份数据):
@WebServlet("/queryProvince")
public class FindProvinceServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AreaDao dao = new AreaDaoImpl();
List<Area> provinceList = dao.findProvinceList();
//java->json
JSONArray jsonArray = JSONArray.fromObject(provinceList);
//输出json数据,响应ajax请求的,返回数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.println(jsonArray);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
FindCityServlet.java(返回城市和地区数据):
@WebServlet("/queryCity")
public class FindCityServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AreaDao dao = new AreaDaoImpl();
int parentid = Integer.parseInt(req.getParameter("parentid"));
List<Area> cityList = dao.findCityList(parentid);
JSONArray jsonArray = JSONArray.fromObject(cityList);
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.println(jsonArray);
}
}
FindAreaServlet.java(返回点击省份时出现的地区数据):
@WebServlet("/queryArea")
public class FindAreaServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AreaDao dao = new AreaDaoImpl();
int parentid = Integer.parseInt(req.getParameter("parentid"));
List<Area> areaList = dao.findAreaList(parentid);
JSONArray jsonArray = JSONArray.fromObject(areaList);
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.println(jsonArray);
}
}
7.工具类
druid.properties:
url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8
username=root
password=123
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
minIdle=5
maxWait=3000
DruidUtil.java:
public class DruidUtil {
private static DataSource ds;
static {
try {
Properties ppt = new Properties();
ppt.load(DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(ppt);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从连接池中取出一个连接给用户
* @return
*/
public static Connection getConnection(){
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void close(Connection conn, Statement state, ResultSet rs){
try {
if(rs!=null){
rs.close();
}
} catch (Exception e) {
e.printStackTrace();
}
close(conn,state);
}
public static void close(Connection conn,Statement state){
try {
if(state!=null){
state.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if(conn!=null){
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
难点:
- 当选择回默认的“请选择省份”,城市要显示为“请选择城市”,地区也要显示为“请选择地区”
- 点击省份时,不仅显示城市,地区也要一并出现