本文為「網上圖書商城」系列第二篇,詳細記錄分類模塊的資料庫設計、DAO 層遞歸查詢、前端手風琴菜單渲染完整代碼。
CREATE TABLE `t_category` (
`cid` char(32) NOT NULL COMMENT '分類ID',
`cname` varchar(50) DEFAULT NULL COMMENT '分類名稱',
`pid` char(32) DEFAULT NULL COMMENT '父分類ID,頂級為NULL',
`desc` varchar(100) DEFAULT NULL COMMENT '描述',
`orderBy` int(11) NOT NULL AUTO_INCREMENT COMMENT '排序',
PRIMARY KEY (`cid`),
UNIQUE KEY `cname` (`cname`),
KEY `FK_t_category_t_category` (`pid`),
KEY `orderBy` (`orderBy`),
CONSTRAINT `FK_t_category_t_category` FOREIGN KEY (`pid`) REFERENCES `t_category` (`cid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
設計亮點: 使用 pid 自關聯實現樹狀結構,orderBy 保證同級分類有序。
public List<Category> findAll() throws SQLException {
// 1. 查詢所有一級分類(pid IS NULL)
String sql = "SELECT * FROM t_category WHERE pid IS NULL ORDER BY orderBy";
List<Map<String, Object>> mapList = qr.query(sql, new MapListHandler());
List<Category> parents = toCategoryList(mapList);
// 2. 為每個一級分類遞歸載入子分類
for (Category parent : parents) {
List<Category> children = findByParent(parent.getCid());
parent.setChildren(children);
}
return parents;
}
private List<Category> findByParent(String pid) throws SQLException {
String sql = "SELECT * FROM t_category WHERE pid = ? ORDER BY orderBy";
List<Map<String, Object>> mapList = qr.query(sql, new MapListHandler(), pid);
return toCategoryList(mapList);
}
此處採用遞歸查詢,適合分類層級不深(如 2-3 級)的場景。若層級極深,建議改用閉包表或路徑枚舉模型。
<script language="javascript">
$(function() {
var bar = new Q6MenuBar();
<c:forEach items="${parents}" var="parent">
<c:forEach items="${parent.children}" var="child">
bar.add("${parent.cname}", "${child.cname}",
"/goods/BookServlet?method=findByCategory&cid=${child.cid}", "body");
</c:forEach>
</c:forEach>
});
</script>

public class Category {
private String cid;
private String cname;
private String pid;
private String desc;
private int orderBy;
private List<Category> children; // 子分類集合
// getter/setter 略
}
orderBy(同級最大值 + 1)pid 並重新排序分類模塊是電商系統的基石,設計良好的樹狀結構與高效查詢策略,能支撐後續商品、搜尋、推薦等核心業務。