二话不说,先来看效果图:
呃呃,虽然不是很美观......不过功能实现就好啦~
数据库模型是这样的:
我做了什么工作呢?
简单解释一下,就是通过查数据库,把上面的数据查出来,每一行数据封装成为一个节点,然后拼成一颗树,最后显示在前台。注意:这里的数据是可以动态扩展的。
字段解释:nodeId就是节点的id。pid是 parentId也就是父亲的id,表示该节点是哪个节点的子节点。type=1代表功能,type=0代表菜单。level代表该节点在树的第几层。
OK,大家应该迫不及待想要知道具体实现了.....
满足大家,先来看前端代码:
1 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 3 <html> 4 <head> 5 <% 6 String server_path = request.getContextPath(); 7 %> 8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 9 </head> 10 <!-- bootstrap-treeview 导包--> 11 <link rel="stylesheet" type="text/css" href="<%=server_path %>/bootstrap-3.3.7-dist/css/bootstrap.css" > 12 <link rel="stylesheet" type="text/css" href="<%=server_path %>/bootstrap-3.3.7-dist/treeview/bootstrap-treeview.css"> 13 <script type="text/javascript" src="<%=server_path %>/bootstrap-3.3.7-dist/treeview/jquery.js"></script> 14 <script type="text/javascript" src="<%=server_path %>/bootstrap-3.3.7-dist/treeview/bootstrap-treeview.js"></script> 15 16 <script type="text/javascript"> 17 //选中/取消父节点时选中/取消所有子节点 18 function getChildNodeIdArr(node) { 19 var ts = []; 20 if (node.nodes) { 21 for (x in node.nodes) { 22 ts.push(node.nodes[x].nodeId); 23 if (node.nodes[x].nodes) { 24 var getNodeDieDai = getChildNodeIdArr(node.nodes[x]); 25 for (j in getNodeDieDai) { 26 ts.push(getNodeDieDai[j]); 27 } 28 } 29 } 30 } else { 31 ts.push(node.nodeId); 32 } 33 return ts; 34 } 35 //选中所有子节点时选中父节点 36 function setParentNodeCheck(node) { 37 var parentNode = $("#tree").treeview("getNode", node.parentId); 38 if (parentNode.nodes) { 39 var checkedCount = 0; 40 for (x in parentNode.nodes) { 41 if (parentNode.nodes[x].state.checked) { 42 checkedCount ++; 43 } else { 44 break; 45 } 46 } 47 if (checkedCount === parentNode.nodes.length) { 48 $("#tree").treeview("checkNode", parentNode.nodeId); 49 setParentNodeCheck(parentNode); 50 } 51 } 52 } 53 54 $(function () { 55 $.ajax({ 56 type: "Post", 57 url: '<%= server_path%>/resource/menu', 58 dataType: "json", 59 success: function (result) { 60 $('#tree').treeview({ 61 data: result.list, // 数据源 62 showCheckbox: true, //是否显示复选框 63 highlightSelected: true, //是否高亮选中 64 multiSelect: true, //多选 65 levels : 2, 66 enableLinks : true,//必须在节点属性给出href属性 67 color: "#010A0E", 68 onNodeChecked : function (event,node) { 69 var selectNodes = getChildNodeIdArr(node); //获取所有子节点 70 if (selectNodes) { //子节点不为空,则选中所有子节点 71 $('#tree').treeview('checkNode', [selectNodes, { silent: true }]); 72 } 73 }, 74 onNodeUnchecked : function(event, node) { //取消选中节点 75 var selectNodes = getChildNodeIdArr(node); //获取所有子节点 76 if (selectNodes) { //子节点不为空,则取消选中所有子节点 77 $('#tree').treeview('uncheckNode', [selectNodes, { silent: true }]); 78 } 79 }, 80 81 onNodeExpanded : function(event, data) { 82 83 }, 84 85 onNodeSelected: function (event, data) { 86 //alert(data.nodeId); 87 } 88 89 }); 90 }, 91 error: function () { 92 alert("菜单加载失败!") 93 } 94 }); 95 }) 96 </script> 97 </head> 98 <body> 99 <div id="tree" class="col-sm-2"></div> 100 </body> 101 </html>
你没有看错,就是这么一个文件就搞定啦。。。
对了,导包不要导错了。没有这些包可以去浏览器下载bootstrap treeview包。下不来可来找我要。
okok,然后看神奇的后台代码:
1 @Controller 2 @RequestMapping("/resource") 3 public class ResourceController extends BaseController{ 4 5 @RequestMapping("menu") 6 public void getMenu(HttpServletRequest request,HttpServletResponse response) throws Exception{ 7 json.setResult("no"); 8 Node tree = getTreeJson();//获得一棵树模型的数据 9 //json.setData(tree); 10 json.setList(tree.getNodes()); 11 json.setResult("ok"); 12 response.getWriter().println(mapper.writeValueAsString(json));//把json数据写回前台 13 } 14 15 16 public Node getTreeJson() { 17 List<Resource> reslist = resourceService.loadAll();//从数据库获取所有资源 18 List<Node> nodes = new ArrayList<Node>();//把所有资源转换成树模型的节点集合,此容器用于保存所有节点 19 for(Resource res : reslist){ 20 Node node = new Node(); 21 node.setHref(res.getUrl()); 22 node.setIcon(res.getIcon()); 23 node.setNodeId(res.getNodeId()); 24 node.setPid(res.getPid()); 25 node.setText(res.getName()); 26 nodes.add(node);//添加到节点容器 27 } 28 Node tree = new Node();//重要插件,创建一个树模型 29 Node mt = tree.createTree(nodes);//Node类里面包含了一个创建树的方法。这个方法就是通过节点的信息(nodes)来构建一颗多叉树manytree->mt。 30 //System.out.println(tree.iteratorTree(mt)); 31 return mt; 32 } 33 34 }
以上代码,就是负责把数据库的数据取出来,封装成对应的节点,根据节点创建一颗树,然后封装成json数据传到前台,就那么简单。
看不懂不要紧,上面用了springmvc框架做控制器,如果你没有这环境,又想做测试,你完全可以用其他控制器,servlet都行,只要能把json数据传回前台就行。当然,上面还用了一些组件,这也不要紧,最重要的不就是红色部分的代码嘛,请睁大眼睛:
1 import java.util.ArrayList; 2 import java.util.List; 3 /** 4 * 树形节点模型 5 * @author chenht 6 * 7 */ 8 public class Node { 9 public Node() { 10 this.nodes = new ArrayList<Node>(); 11 } 12 public Node(String nodeId,String pId) { 13 this.nodeId = nodeId; 14 this.pid = pId; 15 this.nodes = new ArrayList<Node>(); 16 } 17 /** 18 * 生成一个节点 19 * @param nodeId 20 * @param pId 21 * @param text 22 * @param icon 23 * @param href 24 */ 25 public Node(String nodeId, String pId, String text, String icon, String href) { 26 super(); 27 this.nodeId = nodeId; 28 this.pid = pId; 29 this.text = text; 30 this.icon = icon; 31 this.href = href; 32 this.nodes = new ArrayList<Node>(); 33 } 34 35 private String nodeId; //树的节点Id,区别于数据库中保存的数据Id。 36 private String pid; 37 private String text; //节点名称 38 private String icon; 39 private String href; //点击节点触发的链接 40 private List<Node> nodes; //子节点,可以用递归的方法读取 41 42 public String getNodeId() { 43 return nodeId; 44 } 45 public void setNodeId(String nodeId) { 46 this.nodeId = nodeId; 47 } 48 49 public String getPid() { 50 return pid; 51 } 52 public void setPid(String pid) { 53 this.pid = pid; 54 } 55 56 public String getText() { 57 return text; 58 } 59 public void setText(String text) { 60 this.text = text; 61 } 62 63 public String getIcon() { 64 return icon; 65 } 66 public void setIcon(String icon) { 67 this.icon = icon; 68 } 69 70 public String getHref() { 71 return href; 72 } 73 public void setHref(String href) { 74 this.href = href; 75 } 76 77 public List<Node> getNodes() { 78 return nodes; 79 } 80 public void setNodes(List<Node> nodes) { 81 this.nodes = nodes; 82 } 83 84 /** 85 * 生成一颗多叉树,根节点为root 86 * @param Nodes 生成多叉树的节点集合 87 * @return root 88 */ 89 public Node createTree(List<Node> Nodes) { 90 if (Nodes == null || Nodes.size() < 0) 91 return null; 92 Node root = new Node("root","0");//根节点自定义,但是要和pid对应好 93 // 将所有节点添加到多叉树中 94 for (Node node : Nodes) { 95 if (node.getPid().equals("0") || node.getPid().equals("root")) {//根节点自定义,但是要和pid对应好 96 // 向根添加一个节点 97 root.getNodes().add(node); 98 } else { 99 addChild(root, node); 100 } 101 } 102 return root; 103 } 104 105 /** 106 * 向指定多叉树节点添加子节点 107 * @param Node 多叉树节点 108 * @param child 节点 109 */ 110 public void addChild(Node Node, Node child) { 111 for (Node item : Node.getNodes()) { 112 if (item.getNodeId().equals(child.getPid())) { 113 // 找到对应的父亲 114 item.getNodes().add(child); 115 break; 116 } else { 117 if (item.getNodes() != null && item.getNodes().size() > 0) { 118 addChild(item, child); 119 } 120 } 121 } 122 } 123 124 /** 125 * 遍历多叉树 126 * @param Node 多叉树节点 127 * @return 128 */ 129 public String iteratorTree(Node Node) { 130 StringBuilder buffer = new StringBuilder(); 131 buffer.append(" "); 132 if (Node != null) { 133 for (Node index : Node.getNodes()) { 134 buffer.append(index.getNodeId() + ","); 135 if (index.getNodes() != null && index.getNodes().size() > 0) { 136 buffer.append(iteratorTree(index)); 137 } 138 } 139 } 140 buffer.append(" "); 141 return buffer.toString(); 142 } 143 144 public static void main(String[] args) { 145 List<Node> nodes = new ArrayList<Node>(); 146 nodes.add(new Node("系统管理", "0")); 147 nodes.add(new Node("角色管理", "系统管理")); 148 nodes.add(new Node("资源管理", "系统管理")); 149 nodes.add(new Node("用户管理", "系统管理")); 150 nodes.add(new Node("添加用户", "用户管理")); 151 nodes.add(new Node("修改用户", "用户管理")); 152 nodes.add(new Node("机票管理", "系统管理")); 153 154 Node tree = new Node(); 155 Node mt = tree.createTree(nodes); 156 System.out.println(tree.iteratorTree(mt)); 157 } 158 159 160 }
欧克欧克,代码就是那么多,一个文件搞定,有人可能不相信。好吧,火狐浏览器下看传回来的参数是这样的:
现在总该相信了吧?到此,基本介绍完啦,惊不惊喜,开不开心?好吧,本文主要的特点是可动态扩展树中的节点,而且与数据库的数据一一对应上。前台用bootstrap的treeview
做展示,想必你看本文之前,已看过不少关于treeview的文章了吧。ps:红色字体是本文重点。