要求:得到无限分类的菜单栏。并且告诉你任何一个节点,都能得到整个菜单。
数据库是mongodb。没有贴全部,只贴部分。
首先一个整体思路是:
1、要有一个能通过父类id得到全部子类id的集合。
2、遍历这些子类集合来把它们的关系关联起来。
代码部分:
建立数据库的查询:
DBCollection collection = GGMongoOperator.getGGBusinessCollection("gg_help_center_v3");//帮助中心表
DBObject query = new BasicDBObject("status",1);
DBObject object = new BasicDBObject("_id",1).append("name", 1).append("pId", 1).append("icon", 1);
DBCursor cursor = collection.find(query, object).sort(new BasicDBObject("add_time",1));
List
其中List
是我公司自己封装的方法。不使用的话,就是用while循环自己来组装数据。
得到的数据格式 key value;比如:
map.put(“_id”,1);
map.put(“name”,”每日头条”)
list.add(map);
…
之后就是为思路1做准备。紧接着上面的代码:
Map<String,Tree> treeMap = new HashMap<String, Tree>();
Map<String, List<String>> pidMap = new HashMap<String, List<String>>();
for (Map<String, Object> map : nodeList) {
//1、我要拿到顶层节点
Object pId = map.get("pId");
String pid = null;
if(pId != null){
pid = pId.toString();
}else{
continue;
}
//2、通过父类id能拿到全部子类的id
if(pidMap.get(pid) == null){
List<String> list = new ArrayList<String>();
list.add(map.get("_id").toString());
pidMap.put(pId.toString(), list);
}else{
List<String> list = pidMap.get(pId.toString());
list.add(map.get("_id").toString());
}
Tree t = new Tree();
t.setParentId(map.get("pId").toString());
t.setName(map.get("name").toString());
t.setId(map.get("_id").toString());
treeMap.put(map.get("_id").toString(), t);
}
List<String> fatherId = new ArrayList<String>(pidMap.keySet());
fatherId.remove("0"); //0代表的是顶级目录的pid,我后面遍历fatherId获得相应的实体类,但是顶级pid是没有相应的实体类的,所以要移除,否则会报null
int size = fatherId.size();
int ii = 0; //我用来做测试,循环多少次
return getTree(fatherId, nodeList.get(0).get("_id").toString(), treeMap, pidMap, new ArrayList<Tree>(), size, ii);
上面的代码中pidMap就是思路1中所说的集合,通过父类id,得到全部的子类id。
treeMap:保存的就是所有数据的实体类。格式是:key:_id, value:实体类。
Tree:这个是我自己定义的pojo类。
属性有:id,name,parentId,List<Tree> childrenList = new ArrayList<
Tree>();
getTree(…)这个方法就是思路2中去遍历各个子类集合中把它们的关系关联起来。
代码如下:
private static List<Tree> getTree(List<String> fatherId, String id, Map<String,Tree> treeMap, Map<String, List<String>> pidMap, List<Tree> result,int size,int ii) {
//先去获取当前对象,在把子节点的treeset到children里面去。
Tree tree = treeMap.get(id); //这个tree就是实体类!
if(tree !=null){ //正常情况下不会为空,出现为空的情况都是因为有脏数据造成的
if(tree.getParentId() == null||"0".equals(tree.getParentId())){
//我这里应该保存的是一级对象,子对象都在一级对象里面
if(!result.contains(tree)){
result.add(tree);
}
}
//若是叶子节点就没有必要走下面的遍历
List<String> childList = pidMap.get(id);
if(childList != null){
//以下遍历是为了找出子节点
for(String c : childList){
Tree childTree = treeMap.get(c);
String pid = childTree.getParentId();
if(id.equals(pid)){
List<Tree> childrenList = tree.getChildrenList();
if(!childrenList.contains(childTree)){
childrenList.add(childTree);
}
}
ii++;
}
}
}
if(size <= 0){//结束
return result;
}
int ss = size-1;
result = getTree(fatherId, fatherId.get(ss), treeMap, pidMap, result, ss,ii);
System.out.println("循环了======================" + ii);
return result;
}
详解————这里我使用了递归:
if(tree.getParentId() == null||"0".equals(tree.getParentId())){
//我这里应该保存的是一级对象,子对象都在一级对象childrenList里面
if(!result.contains(tree)){
result.add(tree);
}
}
这段代码的意思就是当它是顶级节点时就加入result。我这么写是假设它有多个顶级节点。一般情况下就一个。↑
//若是叶子节点就没有必要走下面的遍历
List<String> childList = pidMap.get(id);
if(childList != null){
//以下遍历是为了找出子节点
for(String c : childList){
Tree childTree = treeMap.get(c);
String pid = childTree.getParentId();
if(id.equals(pid)){
List<Tree> childrenList = tree.getChildrenList();
if(!childrenList.contains(childTree)){
childrenList.add(childTree);
}
}
ii++;
}
}
这个遍历就是去遍历子类节点集合把它们都添加到父类的childrenList中去。↑
if(size <= 0){//结束
return result;
}
int ss = size-1;
result = getTree(fatherId, fatherId.get(ss), treeMap, pidMap, result, ss,ii);
System.out.println("循环了======================" + ii);
return result;
这块代码是进行递归的关键。每次递归时,我都从fatherId中取一个id。
fatherId保存的是所有具有子类的id集合,也就是说,叶子节点不在里面,在里面的都是有子类的;↑
还有个要注意的地方:
if(!childrenList.contains(childTree)){
childrenList.add(childTree);
}
这里使用contains是因为childTree是个list数组,不会去重。若不去重,就会造成重复数据。↑
自此关键代码就结束啦!
public class Tree {
/**
* 节点唯一标识
*/
private String id;
/**
* 节点名称
*/
private String name;
/**
* 所属父节点ID
*/
private String parentId;
/**
* 所属父节点对象
*/
//private Tree parentObj;
/**
* 所含子节点
*/
private List childrenList = new ArrayList();
就不详细列出来。。。
完整的代码:
public static List<Tree> getAllNodes2(){
DBCollection collection = GGMongoOperator.getGGBusinessCollection("gg_help_center_v3");//帮助中心表
DBObject query = new BasicDBObject("status",1);
DBObject object = new BasicDBObject("_id",1).append("name", 1).append("pId", 1).append("icon", 1);
DBCursor cursor = collection.find(query, object).sort(new BasicDBObject("add_time",1));
List<Map<String,Object>> nodeList = GGDBCursor.find(cursor);
Map<String,Tree> treeMap = new HashMap<String, Tree>();
Map<String, List<String>> pidMap = new HashMap<String, List<String>>();
for (Map<String, Object> map : nodeList) {
//1、我要拿到顶层节点
Object pId = map.get("pId");
String pid = null;
if(pId != null){
pid = pId.toString();
}else{
continue;
}
//2、通过父类id能拿到全部子类的id
if(pidMap.get(pid) == null){
List<String> list = new ArrayList<String>();
list.add(map.get("_id").toString());
pidMap.put(pId.toString(), list);
}else{
List<String> list = pidMap.get(pId.toString());
list.add(map.get("_id").toString());
}
Tree t = new Tree();
t.setParentId(map.get("pId").toString());
t.setName(map.get("name").toString());
t.setId(map.get("_id").toString());
treeMap.put(map.get("_id").toString(), t);
}
List<String> fatherId = new ArrayList<String>(pidMap.keySet());
fatherId.remove("0");
int size = fatherId.size();
int ii = 0;
return getTree(fatherId, nodeList.get(0).get("_id").toString(), treeMap, pidMap, new ArrayList<Tree>(), size, ii);
}
private static List<Tree> getTree(List<String> fatherId, String id, Map<String,Tree> treeMap, Map<String, List<String>> pidMap, List<Tree> result,int size,int ii) {
//先去获取当前对象,在把子节点的treeset到children里面去。
Tree tree = treeMap.get(id); //这个tree就是那个固定的常量!
if(tree !=null){
if(tree.getParentId() == null||"0".equals(tree.getParentId())){
//我这里应该保存的是一级对象,子对象都在一级对象里面
if(!result.contains(tree)){
result.add(tree);
}
}
//若是叶子节点就没有必要走下面的遍历
List<String> childList = pidMap.get(id);
if(childList != null){
//以下遍历是为了找出子节点
for(String c : childList){
Tree childTree = treeMap.get(c);
String pid = childTree.getParentId();
if(id.equals(pid)){
List<Tree> childrenList = tree.getChildrenList();
if(!childrenList.contains(childTree)){
childrenList.add(childTree);
}
}
ii++;
}
}
}
if(size <= 0){//结束
return result;
}
int ss = size-1;
result = getTree(fatherId, fatherId.get(ss), treeMap, pidMap, result, ss,ii);
System.out.println("循环了======================" + ii);
return result;
}
再加上Tree这个pojo类,就OK啦!