省市聯動是表單開發的經典需求。本文提供一個基於 Java Servlet、jQuery EasyUI、JSON 非同步載入的完整可執行範例,涵蓋後端資料提供、前端元件初始化、聯動邏輯與錯誤處理。
src/ ├── com.scce.servlet/LoadAreaServlet.java ├── com.scce.pojo/Prov.java, City.java WebContent/ ├── UI/ (EasyUI 相關 js/css) └── test1.html
package com.scce.pojo;
public class Prov {
private int id;
private String provinceName;
// getter/setter 省略
}
public class City {
private int id;
private String cityName;
// getter/setter 省略
}
package com.scce.servlet;
import com.scce.pojo.City;
import com.scce.pojo.Prov;
import net.sf.json.JSONArray;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
public class LoadAreaServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset=UTF-8");
PrintWriter out = resp.getWriter();
String provinceId = req.getParameter("provinceID");
if (provinceId == null || provinceId.isEmpty()) {
// 回傳省份列表
ArrayList provs = new ArrayList<>();
provs.add(new Prov(0, "湖北"));
provs.add(new Prov(1, "湖南"));
provs.add(new Prov(2, "廣東"));
provs.add(new Prov(3, "廣西"));
out.print(JSONArray.fromObject(provs).toString());
} else {
// 回傳該省份下的城市
ArrayList cities = new ArrayList<>();
switch (provinceId) {
case "0": // 湖北
cities.add(new City(0, "武漢市"));
cities.add(new City(1, "黃石市"));
cities.add(new City(2, "十堰市"));
break;
case "1": // 湖南
cities.add(new City(0, "長沙市"));
cities.add(new City(1, "岳陽市"));
cities.add(new City(2, "湘潭市"));
break;
case "2": // 廣東
cities.add(new City(0, "廣州市"));
cities.add(new City(1, "深圳市"));
cities.add(new City(2, "珠海市"));
break;
case "3": // 廣西
cities.add(new City(0, "南寧市"));
cities.add(new City(1, "柳州市"));
cities.add(new City(2, "桂林市"));
break;
}
out.print(JSONArray.fromObject(cities).toString());
}
}
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException { doPost(req, resp); }
}
<servlet>
<servlet-name>loadArea</servlet-name>
<servlet-class>com.scce.servlet.LoadAreaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loadArea</servlet-name>
<url-pattern>/LoadAreaServlet</url-pattern>
</servlet-mapping>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>省市二級聯動演示</title>
<link rel="stylesheet" href="UI/themes/default/easyui.css">
<link rel="stylesheet" href="UI/themes/icon.css">
<script src="UI/jquery.min.js"></script>
<script src="UI/jquery.easyui.min.js"></script>
<script src="UI/locale/easyui-lang-zh_TW.js"></script>
<script>
$(function() {
// 1. 初始化省份下拉框
$('#province').combobox({
width: 200,
valueField: 'id',
textField: 'provinceName',
editable: false,
url: 'LoadAreaServlet', // 無參數 → 取省份
method: 'post',
onLoadSuccess: function(data) {
if (data.length > 0) {
var firstId = data[0].id;
$(this).combobox('select', firstId); // 預選第一項
loadCities(firstId); // 載入對應城市
}
},
onSelect: function(rec) {
loadCities(rec.id); // 使用者切換省份時觸發
}
});
});
// 2. 載入城市下拉框
function loadCities(provinceId) {
$('#city').combobox({
width: 200,
valueField: 'id',
textField: 'cityName',
editable: false,
url: 'LoadAreaServlet?provinceID=' + provinceId,
method: 'post',
onLoadSuccess: function(data) {
if (data.length > 0) {
$(this).combobox('select', data[0].id);
}
}
});
}
</script>
</head>
<body style="padding:20px;">
<h3>省市二級聯動選單</h3>
省份:<select id="province"><option>載入中...</option></select>
城市:<select id="city"><option>請先選省份</option></select>
</body>
</html>
| 技術點 | 說明 |
|---|---|
| EasyUI Combobox | data/url 兩種資料源模式,支援 onLoadSuccess/onSelect 事件鉤子 |
| 同一 Servlet 双模式 | 依 provinceID 參數有無決定回傳省份或城市,減少端點 |
| JSON 格式 | [{id:0, provinceName:"湖北"}, ...] 符合 valueField/textField 映射 |
| 級聯觸發時機 | onLoadSuccess (初始化) + onSelect (使用者切換) |
| 編碼一致性 | Servlet 輸出 UTF-8、HTML meta charset、JS 檔案編碼三統一 |
filter: function(q, row) 支援模糊搜尋required: true, missingMessage: '請選擇城市'GET /api/provinces, GET /api/provinces/{id}/citiesresp.setCharacterEncoding("UTF-8")、資料庫連線 URL 含 characterEncoding=utf8rec.id 而非 rec.provinceName