在做项目的过程中,经常会用到树结构。关于树结构的框架我也接触过几个,比如easyui中封装的树,Ztree等。当然这些封装好的框架只需要我们去按照API来使用即可,那么树的实现原理究竟是怎样的。今天用最原始的代码来拼接一下树的组成结构。
效果:
1、表结构
要想出现树结构,那么数据库中必须包含有可以形成树结构的表,也就是可以区分出父节点和子节点。
id:节点ID,pid;父节点id,level:等级标志(根节点为0,根的一级子节点为1,一次类推),name:节点名称
is_leaf:是否为叶子节点
2、根据树的结构进行拼接
在写这个方法前,首先要创建一个StringBuffer,用来讲这些html拼接成一个完整的字符串。
private StringBuffer sbTreeHTML=new StringBuffer();
1. /**
2. * 递归读取分销商树
3. *
4. * 第四步,生成树结构
5. * @param conn
6. * @param id
7. * @param level 控制层次
8. */
9. private void readClientTree(Connection conn,int id,int level)
10. throws SQLException{
11. "select * from t_client where pid=?";
12. null;
13. null;
14. try{
15. pstmt=conn.prepareStatement(sql);
16. 1, id);
17. rs=pstmt.executeQuery();
18. while(rs.next()){
19. "<div>");//每一个节点都作为一个div来出现
20. "\n");//另起一行
21. //遍历树结构的表,根据等级来决定每一个节点前加几个空白。出现缩进的效果。
22. for(int i=0;i<level;i++){
23. "<img src=\"../images/white.gif\">");//空白图片
24. "\n");
25. }
26. //在拼接的时候,要把每个节点的Id和名称读取出来,进行绑定,以便后续操作
27. if(Constants.No.equals(rs.getString("is_leaf"))){
28. //如果不是叶子节点的情况,节点前面为一个"+"的图片
29. "<img alt=\"展开\" style=\"cursor:hand;\" onClick=\"display('"+rs.getInt("id")+"');\" id=\"img"+rs.getInt("id")+"\" src=\"../images/plus.gif\">");
30. "\n");
31. //“+”图片后面跟着一个关闭标志的黄色小图片
32. "<img id=\"im"+rs.getInt("id")+"\" src=\"../images/closedfold.gif\">");
33. "\n");
34. "<a href=\"client_node_crud.jsp?id="+rs.getInt("id")+"\" target=\"clientDispAreaFrame\">"+rs.getString("name")+"</a>");
35. "\n");
36. "<div style=\"display:none;\" id=\"div" + rs.getInt("id") + "\">");
37. "\n");
38. //递归读取子节点
39. "id"),level+1);
40. "</div>");
41. "\n");
42. else{//叶子的情况
43. "<img src=\"../images/minus.gif\">");//减号
44. "\n");
45. "<img src=\"../images/openfold.gif\">");//张开图片
46. "\n");
47. if(Constants.YES.equals(rs.getString("is_client"))){
48. "<a href=\"client_crud.jsp?id="+rs.getInt("id")+"\" target=\"clientDispAreaFrame\">"+rs.getString("name")+"</a>");
49. else{
50. "<a href=\"client_node_crud.jsp?id="+rs.getInt("id")+"\" target=\"clientDispAreaFrame\">"+rs.getString("name")+"</a>");
51. }
52.
53. }
54. "\n");
55. "</div>");//每个div结束标识
56. "\n");
57.
58. }
59. finally{
60. DbUtil.close(rs);
61. DbUtil.close(pstmt);
62. }
63. }
可根据注释来理解整个的拼接过程。
接下来,在树结构中,我们需要给他加点击事件,让节点响应点击事件来出现应有的树的结构的效果。在拼接的过程中响应的时间为display(id)
js:
1. function display(id) {
2. "var div=div"+id);
3. "var img=img"+id);
4. "var im=im"+id);
5. "block"?"none":"block";
6. "block"?"../images/minus.gif":"../images/plus.gif";
7. "block"?"../images/openfold.gif":"../images/closedfold.gif";
8. "block"?"展开":"关闭";
9. }
通过以上描述,树结构基本上就已经成型了。剩下的就是在前台页面中调用此方法即可。
三、删除节点
接下来就是对树的操作了。
分析一下,增删改,只有删除是相对复杂的。它需要考虑的因素比较多,和查询类似,需要考虑是否为叶子节点,如果为非叶子节点,那么就需要进行递归删除它的子节点。还要考虑,删除的节点的父节点下面还有没有其他的子节点,如果没有需要更改父节点为叶子节点。
1. /**
2. * 递归删除
3. * @param conn
4. */
5. public void recursionDelNode(Connection conn,int id)
6. throws SQLException{
7. "select * from t_client where pid=?";
8. null;
9. null;
10. try{
11. pstmt=conn.prepareStatement(sql);
12. 1, id);
13. rs=pstmt.executeQuery();
14. while(rs.next()){
15. //判断如果为非叶子节点,进行递归查询
16. if(Constants.No.equals(rs.getString("is_leaf"))){
17. "id"));
18. }
19. //执行删除操作
20. "id"));
21. }
22. //删除自身节点
23. delNode(conn,id);
24. catch(SQLException e){
25. e.printStackTrace();
26. finally{
27. DbUtil.close(rs);
28. DbUtil.close(pstmt);
29. }
30. }
31.
32.
33.
34.
35. /**
36. * 删除节点
37. * @param conn
38. * @param id
39. */
40. public void delNode(Connection conn,int id)
41. throws SQLException{
42. "delete from t_client where id=?";
43. null;
44. try{
45.
46. pstmt=conn.prepareStatement(sql);
47. 1, id);
48. pstmt.executeUpdate();
49.
50. catch(SQLException e){
51. e.printStackTrace();
52. finally{
53. DbUtil.close(pstmt);
54. }
55. }
以上就是整个关于拼接树结构的核心部分了。树是Web端常用的界面效果,利用它在很多方面可以清晰的表达组织结构,给大家一目了然的效果,了解它的原理以应万变!