企業級應用常需多級分類聯動(如:大分類 → 中分類 → 小分類)。本文展示以 XML 檔案為資料源、JDOM 解析、JSP 為業務層、原生 JS 為前端的完整三級聯動實作,適合無資料庫輕量場景。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE class SYSTEM "product.dtd">
<class>
<class1 className="電腦配件" id="1">
<class2 className="內存" id="1">
<class3 id="1" className="kingmax"/>
<class3 id="2" className="kingston"/>
<class3 id="3" className="samsung"/>
</class2>
<class2 className="硬盤" id="2">
<class3 id="6" className="hithait"/>
<class3 id="7" className="IBM"/>
</class2>
</class1>
<class1 className="食品配件" id="2">...</class1>
</class>
public class ClassService {
private Document dom;
public ClassService() {
SAXBuilder builder = new SAXBuilder();
dom = builder.build(getClass().getResource("product.xml"));
}
public ProductClass[] getAllClass1() { ... } // 遍歷 class1
public ProductClass[] getAllClass2ById(String class1Id) { ... } // 依 class1Id 找 class2
public ProductClass[] getAllClass3ById(String class1Id, String class2Id) { ... } // 依兩層 ID 找 class3
}
ProductClass 為簡單 POJO:id, className。
<%@ page import="com.ajaxlab.ajax.*" contentType="text/html; charset=gb2312"%>
<%
String class1Id = request.getParameter("class1Id");
String class2Id = request.getParameter("class2Id");
if ("".equals(class1Id)) class1Id = null;
if ("".equals(class2Id)) class2Id = null;
ClassService service = new ClassService();
if (class1Id != null && class2Id == null) {
for (ProductClass c : service.getAllClass2ById(class1Id))
out.print(c.getId() + "," + c.getClassName() + "|");
} else if (class1Id != null && class2Id != null) {
for (ProductClass c : service.getAllClass3ById(class1Id, class2Id))
out.print(c.getId() + "," + c.getClassName() + "|");
}
%>
回傳格式:1,內存|2,硬盤|(管線分隔項目,逗號分隔 ID/名稱)。
<select name="select11" id="select11" onchange="doChange()">
<option value="">請選擇分類一</option>
<% for (ProductClass c : service.getAllClass1()) { %>
<option value="<%=c.getId()%>"><%=c.getClassName()%></option>
<% } %>
</select>
<select name="select12" id="select12" onchange="doChange2()"><option value="">請選擇分類二</option></select>
<select name="select13" id="select13"><option value="">請選擇分類三</option></select>
<script>
var http_request = createXHR(); // 同前文跨瀏覽器建立函式
function doChange() {
var v = document.forms[0].select11.value;
sendRequest('GET', 'getClass.jsp?class1Id=' + v + '&class2Id=', null, 'TEXT', populateClass2);
}
function doChange2() {
var f = document.forms[0];
sendRequest('GET', 'getClass.jsp?class1Id=' + f.select11.value + '&class2Id=' + f.select12.value, null, 'TEXT', populateClass3);
}
function populateClass2() {
if (http_request.readyState == 4 && http_request.status == 200) {
var list = http_request.responseText.split('|');
var sel = document.forms[0].select12;
sel.length = 1;
for (var i = 0; i < list.length - 1; i++) {
var t = trim(list[i]).split(',');
sel.add(new Option(t[1], t[0]));
}
}
}
function populateClass3() { ... 同邏輯填 select13 ... }
function trim(s) { return s.replace(/^\s+|\s+$/g, ''); }
</script>
| 層面 | 現狀 | 建議遷移 |
|---|---|---|
| 資料源 | XML 檔案 + JDOM | 資料庫 + JPA/MyBatis,或 Redis 快取分類樹 |
| 業務層 | JSP 混合 Java 代碼 | Spring MVC @RestController 回傳 JSON |
| 前端 | 原生 JS + 全域變數 | Vue/React 元件化,Axios 請求,TypeScript 型別 |
| 資料格式 | 自訂管線分隔字串 | 標準 JSON:[{id:1,name:'內存'}] |