省市區三級聯動是表單開發高頻需求。本文提供從後端數據組裝、JSON 序列化、前端 jQuery/Vue 渲染、懶加載優化的完整方案代碼。
// 實體類
@Data
public class Area {
private Long id;
private String name;
private Long parentId;
private List children = new ArrayList<>();
}
// Service 組裝樹形結構
@Service
public class AreaService {
@Autowired private AreaMapper areaMapper;
public List getProvinceList() {
// 1. 查詢所有省 (parentId=0 或 1)
List provinces = areaMapper.selectByParentId(0L);
// 2. 批量查詢所有市 (優化:一次查詢所有子節點,記憶體組裝)
List allCities = areaMapper.selectByParentIds(
provinces.stream().map(Area::getId).collect(Collectors.toList())
);
// 3. 記憶體中構建映射關係
Map> cityMap = allCities.stream()
.collect(Collectors.groupingBy(Area::getParentId));
provinces.forEach(p -> p.setChildren(cityMap.getOrDefault(p.getId(), Collections.emptyList())));
return provinces;
}
// 懶加載接口:按需查詢市/區
public List getChildren(Long parentId) {
return areaMapper.selectByParentId(parentId);
}
}
// Controller 返回 JSON
@RestController
@RequestMapping("/api/area")
public class AreaController {
@Autowired private AreaService areaService;
@GetMapping("/provinces")
public Result> provinces() {
return Result.success(areaService.getProvinceList());
}
@GetMapping("/children/{parentId}")
public Result> children(@PathVariable Long parentId) {
return Result.success(areaService.getChildren(parentId));
}
}
| 場景 | 推薦結構 | 優點 | 缺點 |
|---|---|---|---|
| 數據量小 (<5000 條)、首屏需全量 | 完整樹形 JSON (省含市,市含區) | 零後續請求,極快 | 首屏包大,記憶體佔用高 |
| 數據量大、移動端、弱網 | 懶加載:省/市/區分級接口 | 按需載入,首屏快 | 多次請求,需處理 loading |
| 搜索/選擇器組件 | 扁平列表 + parentId 字段 | 支援虛擬滾動、關鍵字過濾 | 需前端構建樹或遞歸查找 |
@Cacheableidx_parent_id,查詢毫秒級name_zh, name_en, name_hk,前端按 locale 顯示省市聯動看似簡單,處理好邊界情況、效能體驗、代碼可維護性,才是工程師的專業度體現。