在做项目中经常会用到地区的树形结构,而在数据库中我们一般存储的是一个地区ID,该地区对应的父节点ID,地区名称。下面仅以安徽省为例展示地区表结构:省 - 市 - 县
areaId parentId areaName
136 13 淮南市
135 13 蚌埠市
143 13 阜阳市
139 13 铜陵市
149 13 宣城市
133 13 合肥市
147 13 亳州市
138 13 淮北市
142 13 滁州市
。。。。。。
856 135 怀远县
857 135 五河县
858 135 固镇县
。。。。。。
需要列出中国每个省下面的市和县。
一种方法是通过表的自连接查询实现,这里不再描述。
第二种方法通过一次sql查询出所有的数据,接着通过递归技术每个省-市,每个省-(市、县)或只有县。
// typeMap 生成t_area表中父节点的所有子孙节点
Map<Integer, Set<Integer>> typeMap = new HashMap<Integer, Set<Integer>>();
// typeDirectMap 生成t_area表中父节点的所有直接子节点
Map<Integer, Set<Integer>> typeDirectMap = new HashMap<Integer, Set<Integer>>(); // parentKey-typeKey
List<TArea> areaList = areaService.getArea();
for (TArea area : areaList) {
Integer typeKey = area.getTypeKey();
Integer parentKey = area.getParentKey();
Set<Integer> set = typeMap.get(parentKey);
if (null != set) {
set.add(typeKey);
} else {
Set<Integer> newSet = new CopyOnWriteArraySet<Integer>();
newSet.add(typeKey);
typeMap.put(parentKey, newSet);
}
}
typeDirectMap.putAll(typeMap);
traverseTypeMap(typeMap);
/**
* 遍历typeMap中所有parent下面的直接child.
*
* @param typeMap
*/
private static void traverseTypeMap(Map<Integer, Set<Integer>> typeMap) {
Set<Entry<Integer, Set<Integer>>> set = typeMap.entrySet();
for (Entry<Integer, Set<Integer>> entry : set) {
Integer parentKey = entry.getKey();
Set<Integer> childSet = entry.getValue();
traverseChild(childSet, parentKey, typeMap);
}
}
/**
* 遍历childSet
*
* @param childSet
* @param pk
* @param typeMap
*/
private static void traverseChild(Set<Integer> childSet, Integer pk,
Map<Integer, Set<Integer>> typeMap) {
for (Integer child : childSet) {
addAllChildToParent(pk, typeMap, child);
}
}
/**
*
* @param pk 父节点
* @param typeMap
* @param ch 子节点
*/
private static void addAllChildToParent(Integer pk, Map<Integer, Set<Integer>> typeMap, Integer ch) {
Set<Integer> set = typeMap.get(pk);
Set<Integer> chSet = typeMap.get(ch);
if (null != chSet) {
Set<Integer> parentSet = new HashSet<Integer>();
addParent(typeMap, pk, parentSet);
for (Integer p : parentSet) {
typeMap.get(p).addAll(chSet); // 把当前子节点的集合加入到父节点的所有祖先集合中
}
set.addAll(chSet); // 把当前子节点的集合加入到父节点集合中
traverseChild(chSet, ch, typeMap);
} else { // 当前子节点集合为空 返回
return;
}
}
/**
* 把当前节点pk的所有祖先节点加入到parentSet中.
*
* @param typeMap
* @param pk
* @param parentSet
*/
private static void addParent(Map<Integer, Set<Integer>> typeMap, Integer pk, Set<Integer> parentSet) {
Set<Entry<Integer, Set<Integer>>> set = typeMap.entrySet();
for (Entry<Integer, Set<Integer>> entry : set) {
Integer key = entry.getKey();
Set<Integer> value = entry.getValue();
if (value.contains(pk)) {
parentSet.add(key);
addParent(typeMap, key, parentSet);
} else {
return; // 是顶级父节点
}
}
}