递归、嵌套for循环、map集合方式实现树形结构菜单列表查询

有时候, 我们需要用到菜单列表,但是怎么样去实现一个菜单列表的编写呢,这是一重要的问题。

比如我们需要编写一个树形结构的菜单,那么我们可以使用JQuery的zTree插件:http://www.treejs.cn/v3/main.php#_zTreeInfo

例如现在需要编写一个这样的菜单列表。那么就可以使用JQuery的zTree插件。

先看一下数据库表结构。

CREATE TABLE `permission` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `pid` int(11) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

1、前端页面。

                <div class="panel-body">

                    <ul id="permissionTree" class="ztree"></ul>

                </div>
<script>
   $(function () {

       var setting = {
           async: {
               enable: true,
               url:"${APP_PATH}/permission/loadData",
               autoParam:["id", "name=n", "level=lv"],
               otherParam:{"otherParam":"zTreeAsyncTest"},
           }


       };

        //树形结构
       $.fn.zTree.init($("#permissionTree"), setting);
    });
</script>

2、在这里呢,我使用的是ssm框架。所以就提交到controller层来进行操作。

Permission类的代码

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class Permission {
 5 
 6     private Integer id;
 7     private String name;
 8     private String url;
 9     private Integer pid;
10     private boolean open = true;
11     private boolean checked = false;
12     private String icon;
13     private List<Permission> children = new ArrayList<Permission>();
14     
15     public boolean isChecked() {
16         return checked;
17     }
18     public void setChecked(boolean checked) {
19         this.checked = checked;
20     }
21     public String getIcon() {
22         return icon;
23     }
24     public void setIcon(String icon) {
25         this.icon = icon;
26     }
27     public Integer getId() {
28         return id;
29     }
30     public void setId(Integer id) {
31         this.id = id;
32     }
33     public String getName() {
34         return name;
35     }
36     public void setName(String name) {
37         this.name = name;
38     }
39     public String getUrl() {
40         return url;
41     }
42     public void setUrl(String url) {
43         this.url = url;
44     }
45     public Integer getPid() {
46         return pid;
47     }
48     public void setPid(Integer pid) {
49         this.pid = pid;
50     }
51     public boolean isOpen() {
52         return open;
53     }
54     public void setOpen(boolean open) {
55         this.open = open;
56     }
57     public List<Permission> getChildren() {
58         return children;
59     }
60     public void setChildren(List<Permission> children) {
61         this.children = children;
62     }
63     
64 }

 使用controller这里我使用三种方式来进行查找 。

  (1)递归方式读取各节点

controller层

    /**
     * 异步加载树结点
     * @return
     */
    @RequestMapping("/loadData")
    @ResponseBody
    public List<Permission> loadData(){
        // 递归查询数据
    Permission parent = new Permission();
    parent.setId(0);
    queryChildPermissions(parent);
    return parent.getChildren();        
    }
    /**
     * 递归查询许可信息
     * 1) 方法自己调用自己
     * 2)方法一定要存在跳出逻辑
     * 3)方法调用时,参数之间应该有规律
     * 4) 递归算法,效率比较低
     * @param parent
     */
    private  void queryChildPermissions(Permission parent){
        List<Permission> childPermissions = permissionService.queryChildPermissions(parent.getId());
        for (Permission permission :childPermissions) {
            queryChildPermissions(permission);
        }
        parent.setChildren(childPermissions);
    }

 service层

    public Permission queryRootPermission() {
        return permissionMapper.queryRootPermission();
    }

 mappern层

    @Select("select * from permission where pid is null")
    Permission queryRootPermission();

  (2)嵌套for循环方式读取各节点

controller层

 1     /**
 2      * 异步加载树结点
 3      * @return
 4      */
 5     @RequestMapping("/loadData")
 6     @ResponseBody
 7     public List<Permission> loadData(){
 8         List<Permission> permissions=new ArrayList<Permission>();
 9         // 查询所有的许可数据
10         List<Permission> ps = permissionService.queryAll();
11         for ( Permission p : ps ) {
12             // 子节点
13             Permission child = p;
14             if ( p.getPid() == 0 ) {
15                 permissions.add(p);
16             } else {
17                 for ( Permission innerPermission : ps ) {
18                     if ( child.getPid().equals(innerPermission.getId()) ) {
19                         // 父节点
20                         Permission parent = innerPermission;
21                         // 组合父子节点的关系
22                         parent.getChildren().add(child);
23                         break;
24                     }
25                 }
26             }
27         }
28 
29 
30        return permissions;
31     }

 service层

    public List<Permission> queryAll() {
        return permissionMapper.queryAll();
    }

mapper层

    @Select("select * from permission")
    List<Permission> queryAll();

   (3)map集合方式读取各节点

 controller层

    /**
     * 异步加载树结点
     * @return
     */
    @RequestMapping("/loadData")
    @ResponseBody
    public List<Permission> loadData(){
        List<Permission> permissions=new ArrayList<Permission>();

        // 查询所有的许可数据
        List<Permission> ps = permissionService.queryAll();

        Map<Integer, Permission> permissionMap = new HashMap<Integer, Permission>();
        for (Permission p : ps) {
            permissionMap.put(p.getId(), p);
        }
        for ( Permission p : ps ) {
            Permission child = p;
            if ( child.getPid() == 0 ) {
                permissions.add(p);
            } else {
                Permission parent = permissionMap.get(child.getPid());
                parent.getChildren().add(child);
            }
        }
       return permissions;
    }

service层

    public List<Permission> queryAll() {
        return permissionMapper.queryAll();
    }

mapper层

    @Select("select * from permission")
    List<Permission> queryAll();

三种方法的总结 :

使用递归会使数据库查询非常频繁,不能进行性能优化

使用嵌套for循环没有使用索引,不够快速

使用map集合就使用了索引,加快查询速度。

原文地址:https://www.cnblogs.com/limn/p/9515248.html