递归、嵌套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集合就使用了索引,加快查询速度。