要求:得到无限分类的菜单栏。并且告诉你任何一个节点,都能得到整个菜单。
数据库是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<Map<String,Object>> nodeList = GGDBCursor.find(cursor);
其中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
>(); - 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
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<Tree> childrenList = new ArrayList<Tree>();
就不详细列出来。。。
完整的代码:
- 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
>(); - 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
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啦!