Java 实现树形结构

       树形结构可以清楚地呈现数据的从属关系,在数据库中我们可以用自关联来保存这样的关系。但是在取出数据的时候,如果采用以往的手段,免不了要进行递归操作。递归在理论上是可以解决树形结构的问题,但是如果数据量够大,目录层次够深,我们递归出层次关系是比较消耗资源的。我们可以从数据结构入手,树有它的分支,每个分支又可以延伸出新的分支,那么我们可以在每个节点中增加它的左支和右支,左支和右支良好的维护了树形体系。父节点的左支是永远小于子节点的左支,父节点的右支是永远大于子节点的右支,有了这样的关系,我们想要表现出树形结构是很简单的。所以我们将数据库表设计为自关联表,每个记录中都维护着一个坐支和右支。不必在表中添加父节点列也可以轻松搞定树状关系。

效果图:

 

 

Dao层

package cn.dk.dao;

import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import cn.dk.domain.Category;
import cn.dk.utils.JdbcUtils;

public class CategoryDao {

	@SuppressWarnings("unchecked")
	public List<Category> selectAllCategory() {
		QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
		String sql = "select c.id,c.name,c.left_hand,c.right_hand,count(c.name) depth from category p,category c where p.left_hand<=c.left_hand and p.right_hand>=c.right_hand group by c.name order by c.left_hand";
		try {
			return (List<Category>) runner.query(sql, new BeanListHandler(
					Category.class));
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public Category selectCategory(String id) {
		QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
		String sql = "select id,name,left_hand,right_hand from category where id=?";
		Object[] params = { id };
		try {
			return (Category) runner.query(sql,
					new BeanHandler(Category.class), params);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public void insertCategory(Category category) {
		QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
		String sql = "insert into category values(?,?,?,?)";
		Object[] params = { category.getId(), category.getName(),
				category.getLeft_hand(), category.getRight_hand() };
		try {
			runner.update(sql, params);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	@SuppressWarnings("unchecked")
	public List<Category> selectParent(String id) {
		QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
		String sql = "select p.id,p.name,p.left_hand,p.right_hand from category p,category c where p.left_hand <= c.left_hand and p.right_hand >= c.right_hand and c.id=? order by p.left_hand";
		Object[] params = { id };
		try {
			return (List<Category>) runner.query(sql, new BeanListHandler(
					Category.class), params);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public void updateCategory(int left_hand) {
		String sql = "update category set left_hand=left_hand+2 where left_hand>? ";
		QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
		try {
			runner.update(sql, left_hand);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
		sql = "update category set right_hand=right_hand+2 where right_hand>=? ";
		try {
			runner.update(sql, left_hand);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
}


Service 层

package cn.dk.service;

import java.util.List;
import java.util.UUID;

import cn.dk.dao.CategoryDao;
import cn.dk.domain.Category;

public class CategoryService {

	public List<Category> selectAllCategory(){
		CategoryDao categoryDao = new CategoryDao();
		return categoryDao.selectAllCategory();
	}
	
	public List<Category> selectParents(String id){
		CategoryDao categoryDao = new CategoryDao();
		return categoryDao.selectParent(id);
	}
	
	public void insertCategory(String name, String parentId){
		CategoryDao categoryDao = new CategoryDao();
		Category parent = categoryDao.selectCategory(parentId);
		
		Category child = new Category();
		child.setId(UUID.randomUUID().toString());
		child.setName(name);
		child.setLeft_hand(parent.getRight_hand());
		child.setRight_hand(parent.getRight_hand() + 1);
		
		categoryDao.updateCategory(child.getLeft_hand());
		categoryDao.insertCategory(child);
	}
}

 

Web 层

package cn.dk.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.dk.service.CategoryService;

@SuppressWarnings("serial")
public class InsertCategoryServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		String id = request.getParameter("id");
		String name = request.getParameter("name");
		CategoryService serivice = new CategoryService();
		serivice.insertCategory(name, id);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}
}

 
package cn.dk.web;

import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.dk.domain.Category;
import cn.dk.service.CategoryService;

@SuppressWarnings("serial")
public class SelectAllCategoryServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		CategoryService service = new CategoryService();
		List<Category> cList = service.selectAllCategory();
		request.setAttribute("category", cList);
		request.getRequestDispatcher("/WEB-INF/pages/showList.jsp").forward(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

package cn.dk.web;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.dk.domain.Category;
import cn.dk.service.CategoryService;

@SuppressWarnings("serial")
public class ShowInsertServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		CategoryService service = new CategoryService();
		String id = request.getParameter("id");
		List<Category> parent = service.selectParents(id);
		request.setAttribute("parent", parent);
		request.setAttribute("id", id);
		request.getRequestDispatcher("/WEB-INF/pages/insert.jsp").forward(request,
				response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}


Jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  	<script type="text/javascript" src="${pageContext.request.contextPath }/js/xtree.js"></script>
  	<link type="text/css" href="${pageContext.request.contextPath }/css/xtree.css">
  </head>
  
  <body>
  	<script type="text/javascript">
  		<c:forEach var="ctg" items="${requestScope.category}">
	  		<c:if test="${ctg.depth==1}">
	  			var root = new WebFXTree('${ctg.name }');
	  			root.setBehavior('explorer');
	  			root.action="${pageContext.request.contextPath}/servlet/ShowInsertServlet?id=${ctg.id}";
	  			root.target="main";
	  		</c:if>
			<c:if test="${ctg.depth==2}">
	  			var node${ctg.depth } = new WebFXTreeItem('${ctg.name }');
	  			node${ctg.depth}.action="${pageContext.request.contextPath}/servlet/ShowInsertServlet?id=${ctg.id}";
	  			node${ctg.depth}.target="main";
	  			root.add(node${ctg.depth });
	  		</c:if> 
	  		<c:if test="${ctg.depth>2}">
	  			var node${ctg.depth } = new WebFXTreeItem('${ctg.name }');
	  			node${ctg.depth}.action="${pageContext.request.contextPath}/servlet/ShowInsertServlet?id=${ctg.id}";
	  			node${ctg.depth}.target="main";
	  			node${ctg.depth-1 }.add(node${ctg.depth });
	  		</c:if>  		
  		</c:forEach>
  		document.write(root);
  	</script>
  </body>
</html>
 
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  </head>
  
  <body>
    <br><br>
    您当前的位置 : 
    <c:forEach var="p" items="${requestScope.parent}" >
    	${p.name }>>>
    </c:forEach>
    <form action="${pageContext.request.contextPath }/servlet/InsertCategoryServlet?id=${requestScope.id }" method="post">
    	<input type="text" name="name" >
    	<input type="submit" value="增加节点">
    </form>	
  </body>
</html>


 

 




$(function(){ $.fn.extend({ SimpleTree:function(options){ //初始化参数 var option = $.extend({ click:function(a){ } },options); option.tree=this; /* 在参数对象中添加对当前菜单树的引用,以便在对象中使用该菜单树 */ option._init=function(){ /* * 初始化菜单展开状态,以及分叉节点的样式 */ this.tree.find("ul ul").hide(); /* 隐藏所有子级菜单 */ this.tree.find("ul ul").prev("li").removeClass("open"); /* 移除所有子级菜单父节点的 open 样式 */ this.tree.find("ul ul[show='true']").show(); /* 显示 show 属性为 true 的子级菜单 */ this.tree.find("ul ul[show='true']").prev("li").addClass("open"); /* 添加 show 属性为 true 的子级菜单父节点的 open 样式 */ }/* option._init() End */ /* 设置所有超链接不响应单击事件 */ this.find("a").click(function(){ $(this).parent("li").click(); return false; }); /* 菜单项 接受单击 */ this.find("li").click(function(){ /* * 当单击菜单项 * 1.触发用户自定义的单击事件,将该 标签中的第一个超链接做为参数传递过去 * 2.修改当前菜单项所属的子菜单的显示状态(如果等于 true 将其设置为 false,否则将其设置为 true) * 3.重新初始化菜单 */ option.click($(this).find("a")[0]); /* 触发单击 */ /* * 如果当前节点下面包含子菜单,并且其 show 属性的值为 true,则修改其 show 属性为 false * 否则修改其 show 属性为 true */ /* if($(this).next("ul").attr("show")=="true"){ $(this).next("ul").attr("show","false"); }else{ $(this).next("ul").attr("show","true"); }*/ /* 初始化菜单 */ option._init(); }); /* 设置所有父节点样式 */ this.find("ul").prev("li").addClass("folder"); /* 设置节点“是否包含子节点”属性 */ this.find("li").find("a").attr("hasChild",false); this.find("ul").prev("li").find("a").attr("hasChild",true); /* 初始化菜单 */ option._init(); }/* SimpleTree Function End */ }); });
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值