最后效果图是这样的(看起来有点丑,只是没有美化,效果还是不错的):
一、树结构的数据库储存表设计:
树结构在数据库储存一般会使用加内关联键的方式,表看起来如下:
但是用这种表结构查询时总是要迭代,如果运用树结构的特点来建表,则查询和数据处理会好得多,具体表结构看起来如下:
数据库建表语句为:
create table category ( id varchar(30) primary key, name varchar(30), lft int unique, rgt int unique );
获取树结构的查询语句为:
select child.id,child.name,count(child.name) depth from category parent,category child where
child.lft>=parent.lft and child.rgt<=parent.rgt group by child.name order by child.lft;
得到的结果为:
让后将表格封装为对象,domain与dao的代码有:
class Category { private String id; private String name; private int lft; private int rgt; private int depth;
...........
public class CategoryDao { private QueryRunner qr = new QueryRunner(DaoUtils.getDataSource()); public void add(Category category) { try { //先更新,使所有let与rgt>=category.lft的都加2,为插入提供位置 String sql = "update category set rgt=rgt+2 where rgt>=?"; qr.update(sql, category.getLft()); sql = "update category set lft=lft+2 where lft>=?"; qr.update(sql,category.getLft()); //插入 sql = "insert into category(id,name,lft,rgt) values(?,?,?,?)"; qr.update(sql, category.getId(), category.getName(), category.getLft(), category.getRgt()); } catch (SQLException e) { throw new RuntimeException(e); } } //删除一个节点,以及其下面所有子节点 public void delete(String id) { try { Category category = find(id); String sql = "delete from category where lft>=? and rgt<=?"; qr.update(sql, category.getLft(),category.getRgt()); } catch (SQLException e) { throw new RuntimeException(e); } } public Category find(String id) { String sql = "select name,lft,rgt from category where id=?"; try { Category category = qr.query(sql, new BeanHandler<Category>(Category.class), id); category.setId(id); return category; } catch (SQLException e) { throw new RuntimeException(e); } } public List<Category> getTree(){ String sql = "select child.id,child.name,count(child.name) depth from category parent,category child where child.lft>=parent.lft and child.rgt<=parent.rgt group by child.name order by child.lft"; try { List<Category> categories = qr.query(sql, new BeanListHandler<Category>(Category.class)); return categories; } catch (SQLException e) { throw new RuntimeException(e); } } }
最后sevlet调用jsp输出即可:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Category> tree = new TreeService().getTree(); request.setAttribute("tree",tree); request.getRequestDispatcher(request.getContextPath()+"/WEB-INF/jsp/tree.jsp").forward(request,response); }
<%@ page import="com.hao.domain.Category" %> <%@ page import="java.util.List" %> <%@ page import="java.util.ArrayList" %><%-- Created by IntelliJ IDEA. User: 28602 Date: 2018/2/10 Time: 16:32 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <HTML> <HEAD> <TITLE> ZTREE DEMO </TITLE> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="../css/zTreeStyle/zTreeStyle.css" type="text/css"> <style> body { background-color: white; margin: 0; padding: 0; text-align: center; } div, p, table, th, td { list-style: none; margin: 0; padding: 0; color: #333; font-size: 12px; font-family: dotum, Verdana, Arial, Helvetica, AppleGothic, sans-serif; } #testIframe { margin-left: 10px; } </style> <script type="text/javascript" src="../js/jquery-1.4.4.min.js"></script> <script type="text/javascript" src="../js/jquery.ztree.core.js"></script> <SCRIPT type="text/javascript"> var zTree; var demoIframe; var setting = { view: { dblClickExpand: false, showLine: true, selectedMulti: false }, data: { simpleData: { enable: true, idKey: "id", pIdKey: "pId", rootPId: "" } }, callback: { beforeClick: function (treeId, treeNode) { var zTree = $.fn.zTree.getZTreeObj("tree"); if (treeNode.isParent) { zTree.expandNode(treeNode); return false; } else { demoIframe.attr("src", treeNode.file + ".html"); return true; } } } }; var zNodes = [ <% //元素自上而下遍历,list作为储存可能插入元素的集合,其index为深度 List<Category> list = new ArrayList<>(); Category category = new Category(); category.setId("0"); list.add(0,category); request.setAttribute("list",list); %> <c:forEach var="ca" items="${tree}"> <% Category ca =(Category) pageContext.getAttribute("ca"); list.add(ca.getDepth(),ca); %> {id:${ca.id}, pId: ${list[ca.depth-1].id}, name: "${ca.name}", open: true}, </c:forEach> ]; $(document).ready(function () { var t = $("#tree"); t = $.fn.zTree.init(t, setting, zNodes); demoIframe = $("#testIframe"); demoIframe.bind("load", loadReady); var zTree = $.fn.zTree.getZTreeObj("tree"); zTree.selectNode(zTree.getNodeByParam("id", 101)); }); function loadReady() { var bodyH = demoIframe.contents().find("body").get(0).scrollHeight, htmlH = demoIframe.contents().find("html").get(0).scrollHeight, maxH = Math.max(bodyH, htmlH), minH = Math.min(bodyH, htmlH), h = demoIframe.height() >= maxH ? minH : maxH; if (h < 530) h = 530; demoIframe.height(h); } </SCRIPT> </HEAD> <BODY> <TABLE border=0 height=600px align=left> <TR> <TD width=500px align=left valign=top style="BORDER-RIGHT: #999999 "> <ul id="tree" class="ztree" style="width:260px; overflow:auto;"></ul> </TD> </TR> </TABLE> </BODY> </HTML>
jsp输出使用到了ztree框架下载地址:zTree