树形结构——基本原理
2014-10-12 22:25
232 查看
说明
首先需要声明,本篇博客是实现单实体的最基本的树形结构效果,不涉及第三方组件内容。万变不离其宗,无论是通过哪种方式,其基本的思路还是一致,希望通过本篇博客的讲解,能对初次研究树形结构的朋友有所启发。后面是实现界面显示公司规模结构效果的例子。实现
数据库对应表结构:为方便程序实现,我们将区域和公司信息,统一放入公司信息表。
再来看V层JSP页面呈现:
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@ page import="com.tgb.basetree.manager.*" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB18030">
<link rel="stylesheet" href="../style/drp.css">
<title>组织结构</title>
</head>
<body class="body1">
<table>
<tr>
<td valign="top" nowrap="nowrap">
<%=CompanyTreeReader.getInstance().getClientTreeHTMLString() %>
</td>
</tr>
</table>
</body>
</html> CompanyTreeReader类中调用了getClientTreeHTMLString方法,实现如下:
//定义返回给客户端的HTML字符串
private StringBuffer sbTreeHTML = new StringBuffer();
/**
* 方法入口(为递归调用提供统一的数据库连接)
* @return 返回HTML字符串
*/
public String getClientTreeHTMLString(){
//递归调用时使用同一连接字符串,避免多次与数据库进行连接
Connection conn = null;
try{
conn = DbUtil.getConnection();
//调用递归实现读取的方法,第二个参数设置为0,则表示从根节点读取
readCompanyTree(conn, 0, 0);
}catch(Exception e){
e.printStackTrace();
}finally{
//关闭数据库连接
DbUtil.close(conn);
}
return sbTreeHTML.toString();
}
然后,我们从最简单的查询数据库开始实现拼接界面要显示的HTML树形结构页面的效果
1.首先我们实现最简单的查询,可以显示到浏览器中即可
/**
* 递归读取公司表的数据信息
*
* 第一步: 以最简单的方式读取分销商树形结构,可以显示到浏览器中即可
* @param conn
* @param id
* @param leavel 控制层次
*/
private void readCompanyTree(Connection conn, int id, int leavel)
throws SQLException{
PreparedStatement pstmt = null;
ResultSet result = null;
//查询字符串
String strSql = "Select id, pid, name, company_id, contact_tel, address, is_company, zip_code, is_leaf from t_company where pid=?";
try{
pstmt = conn.prepareStatement(strSql);
//查询语句参数赋值
pstmt.setInt(1, id);
result = pstmt.executeQuery();
//遍历查询结果集
while(result.next()){
//拼接HTML字符串
sbTreeHTML.append(result.getString("name"));
sbTreeHTML.append("<br />\n");
//不是叶子节点,递归调用执行
if("N".equals(result.getString("is_leaf"))){
readCompanyTree(conn,Integer.parseInt(result.getString("id")),leavel);
}
}
}finally{
//执行结束关闭资源
DbUtil.close(result);
DbUtil.close(pstmt);
}
}
界面显示效果:
2.实现分层显示效果
/**
* 递归读取公司表的数据信息
*
* 第二步: 加入层次感,并在叶子节点前加“-”号,非叶子节点前加“+”
* @param conn 数据库连接字符串
* @param id 根据pid查询的关键字值
* @param leavel 控制层次
*/
private void readCompanyTree(Connection conn, int id, int level)
throws SQLException{
PreparedStatement pstmt = null;
ResultSet result = null;
//查询字符串
String strSql = "Select id, pid, name, company_id, contact_tel, address, is_company, zip_code, is_leaf from t_company where pid=?";
try{
pstmt = conn.prepareStatement(strSql);
//查询语句参数赋值
pstmt.setInt(1, id);
result = pstmt.executeQuery();
//遍历查询结果集
while(result.next()){
//获取level值,得出空格个数
for(int i=0; i < level; i++){
sbTreeHTML.append(" ");
}
if("N".equals(result.getString("is_leaf"))){
sbTreeHTML.append("+")
.append(result.getString("name"))
.append("<br />\n");
//不是叶子节点,递归调用执行,level层次参数同步递增
readCompanyTree(conn,result.getInt("id"),level+1);
}else{
sbTreeHTML.append("-")
.append(result.getString("name"))
.append("<br />\n");
}
}
}finally{
//执行结束关闭资源
DbUtil.close(result);
DbUtil.close(pstmt);
}
}
界面显示:
3.JS控制显示隐藏节点效果
再开始继续完善之前,我们首先看不存在数据交换的树形结构的纯HTML方式
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <script language="JavaScript"> //根据传入id值,确定显示/隐藏嵌套的div的ID值,进而切换显示/隐藏效果 function display(id) { eval("var div=div"+id); eval("var img=img"+id); eval("var im=im"+id); div.style.display=div.style.display=="block"?"none":"block"; img.src=div.style.display=="block"?"../images/minus.gif":"../images/plus.gif"; im.src=div.style.display=="block"?"../images/openfold.gif":"../images/closedfold.gif"; img.alt=div.style.display=="block"?"关闭":"展开"; } </script> </head> <body class="body1"> <table> <tr> <td valign="top" nowrap="nowrap"> <div> <img alt="展开" style="cursor:hand;" onClick="display('1');" id="img1" src="../images/plus.gif"> <img id="im1" src="../images/closedfold.gif"> <a href="#" target="clientDispAreaFrame">所有分销商</a> <div style="display:none;" id="div1"> <div> <img src="../images/white.gif"> <img alt="展开" style="cursor:hand;" onClick="display('2');" id="img2" src="../images/plus.gif"> <img id="im2" src="../images/closedfold.gif"> <a href="#" target="clientDispAreaFrame">华北区</a> <div style="display:none;" id="div2"> <div> <img src="../images/white.gif"> <img src="../images/white.gif"> <img alt="展开" style="cursor:hand;" onClick="display('3');" id="img3" src="../images/plus.gif"> <img id="im3" src="../images/closedfold.gif"> <a href="#" target="clientDispAreaFrame">北京市</a> <div style="display:none;" id="div3"> <div> <img src="../images/white.gif"> <img src="../images/white.gif"> <img src="../images/white.gif"> <img src="../images/minus.gif"> <img src="../images/openfold.gif"> <a href="#" target="clientDispAreaFrame">北京总公司</a> </div> </div> </div> </div> </div> <div> <img src="../images/white.gif"> <img src="../images/minus.gif"> <img src="../images/openfold.gif"> <a href="#" target="clientDispAreaFrame">东北区</a> </div> <div> <img src="../images/white.gif"> <img src="../images/minus.gif"> <img src="../images/openfold.gif"> <a href="#" target="clientDispAreaFrame">华南区</a> </div> </div> </div> </td> </tr> </table> </body> </html>
根据上面的模版,我们就可以在后台继续拼成我们最终的HTML代码:
/**
* 递归读取公司信息树
*
* 第三步: 采用DIV生成树形结构
* @param conn
* @param id
* @param leavel 控制层次
*/
private void readCompanyTree(Connection conn, int id, int level)
throws SQLException{
PreparedStatement pstmt = null;
ResultSet result = null;
String strSql = "Select id, pid, name, company_id, contact_tel, address, is_company, zip_code, is_leaf from t_company where pid=?";
try{
pstmt = conn.prepareStatement(strSql);
pstmt.setInt(1, id);
result = pstmt.executeQuery();
while(result.next()){
sbTreeHTML.append("<div>")
.append("\n");
for(int i=0; i < level; i++){
sbTreeHTML.append("<img src=\"images/white.gif\">")
.append("\n");
}
//if("N".equals(result.getString("is_leaf"))){
if("N".equals(result.getString("is_leaf"))){
//拼接字符串过程,对应上面HTML模版中的内容,可进行简要粘贴、简要修改
sbTreeHTML.append("<img alt=\"展开\" style=\"cursor:hand;\" onClick=\"display('"+ result.getInt("id") +"');\" id=\"img"+ result.getInt("id") +"\" src=\"images/plus.gif\">")
.append("\n")
.append("<img id=\"im"+ result.getString("id") +"\" src=\"images/closedfold.gif\">")
.append("\n")
.append("<a href=\"#\">" + result.getString("name") + "</a>")
.append("\n")
.append("<div style=\"display:none;\" id=\"div"+ result.getInt("id") +"\">");
readCompanyTree(conn,result.getInt("id"),level+1);
sbTreeHTML.append("</div>");
}else{
sbTreeHTML.append("<img src=\"images/minus.gif\">")
.append("\n")
.append("<img src=\"images/openfold.gif\">")
.append("\n");
if("N".equals(result.getString("is_company"))){
sbTreeHTML.append("<a href=\"#\" >"+ result.getString("name") +"</a>");
}else{
sbTreeHTML.append("<a href=\"#\" >"+ result.getString("name") +"</a>");
}
}
sbTreeHTML.append("</div>");
}
}finally{
DbUtil.close(result);
DbUtil.close(pstmt);
}
}
最后实现效果:
总结
最后形成的树形结构,是通过对JS代码控制div显示/隐藏的简单应用实现的,整个实现过程的关键点在于:方法的递归调用,后台拼接HTML代码串以及JS的灵活使用。在实际项目中,我们大部分是通过第三方工具来实现树形结构,例如ZTree等,在明白基本原理的层面再去应用,相信会更加清楚明了一些。本篇博客仅仅是从最最基本的实现方式入手,简单阐述并实现树形结构的实例。其中还有很多不足住处,例如多实体的级联操作,冗余字段的影响等内容,在此也仅仅是个入门学习而已。
树形结构作为一项系统中经常用到的一项技术,我们不仅仅需要进行读取、界面显示的效果,对其中节点的CRUD操作更是常见,写至此时,也联想到了设计模式中的组合模式,正是灵活应对树形节点增删改的好方法,后面将会进行更进一步的探讨。
相关文章推荐
- 树形结构——基本原理
- 12.采用左右值编码来存储无限分级树形结构的数据库表设计[摘自网络]
- MongoDB五种树形结构表示法
- javascript+css简单实现树形结构列表
- js 把线性的数据结构改成树形结构
- 输出树形结构的二叉树
- 用DTree实现对所有树形结构的增删改查
- easyui树形结构搜索功能
- Jquery树形表格结构插件(一般用于分类,比如编辑商品的分类、文章的分类等)
- 把自身引用的数据表(树形结构)绑定到TreeView上的控件
- 投诉举报项目中树形结构的应用
- treed树形结构插件应用
- 树形结构部门的 sqlserver 排序
- 树形结构数据的提交
- 【thinkphp】thinkphp递归循环栏目按照树形结构无限极输出
- 组装树形结构循环寻找父子关系速度过慢的一种解决方案
- angular2/4 树形结构菜单示例
- Linux/Ubuntu tree 命令以树形结构显示文件夹目录结构
- C#创建树形结构
- 遍历树形结构