读书人

无限级归类设计

发布时间: 2012-12-20 09:53:21 作者: rapoo

无限级分类设计
最近在弄一个无限级的分类,上网搜了很多资料,感觉都不是很适用,仔细研究了下递归,并参考了老师的程序,终于弄出了点眉目,写出来和大家分享下,直接从项目里面拷出代码,稍做了点修改。
第一次在javaeye上写原创,不足之处请大家谅解。

数据库表的设计
数据库名为:business
表名为:news_class //新闻分类表

为简化说明,只写了3个字段,分别为:
1、newsclass_id //分类ID,int 类型
2、newsclass_parentid //父ID,int 类型,这是分级关键,比如A的ID为B的父ID,说明A是B的父
分类,以次类推,可以一级一级往下无限增长
3、newsclass_title //分类的标题,varchar类型


插入20条记录
+--------------+--------------------+-----------------+
| newsclass_id | newsclass_parentid | newsclass_title |
+--------------+--------------------+-----------------+
| 1 | 0 | title1 |
| 2 | 1 | title2 |
| 3 | 1 | title3 |
| 4 | 1 | title4 |
| 5 | 2 | title5 |
| 6 | 2 | title6 |
| 7 | 2 | title7 |
| 8 | 0 | title8 |
| 9 | 2 | title9 |
| 10 | 2 | title10 |
| 11 | 2 | title11 |
| 12 | 0 | title12 |
| 13 | 0 | title13 |
| 14 | 0 | title14 |
| 15 | 10 | title15 |
| 16 | 1 | title16 |
| 17 | 0 | title17 |
| 18 | 15 | title18 |
| 19 | 0 | pc1 |
| 20 | 18 | 111111 |
+--------------+--------------------+-----------------+

创建数据库连接

package com.common;import java.sql.* ;public class DBConnection {private String DB = "com.mysql.jdbc.Driver" ;private String URL = "jdbc:mysql://localhost/business" ;private String NAME = "root" ;private String PWD = "123456" ;private Connection conn = null ;public DBConnection(){try{Class.forName(DB) ;conn = DriverManager.getConnection(URL,NAME,PWD) ;}catch(Exception e){System.out.println(e);}}public Connection getConnection(){return this.conn ;}public void close(ResultSet rs , PreparedStatement pstm){try{conn.close() ;rs.close();pstm.close() ;}catch(Exception e){System.out.println(e);}}}

递归程序

package com.test ;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;import com.common.DBConnection;import com.vo.NewsClass;public class Test {List l = new ArrayList() ;   DBConnection dbc = new DBConnection() ;   PreparedStatement pstm = null ;/* 这里的int parentid和String sql说明1、parentid就是父ID,想从哪一层开始查询就输入相应的数字,一般父ID为0的是顶级分类,下面程序以父ID为0做演示2、因为我有几个表都要调用到递归,所以我没有把sql写死,设置为从外面传进来,这样不同表就可以有不同的sql语句了 */     public ResultSet child(int parentid,String sql){   ResultSet rs2 = null ;   try{   pstm = dbc.getConnection().prepareStatement(sql) ;   pstm.setInt(1,parentid) ;    rs2 = pstm.executeQuery() ;   }catch(Exception e){    }      return rs2 ;      }   //递归的方法    public void showTree(int parentid,int level,String sql)throws Exception{ //level就是用于分出层次结构     ResultSet rs = child(parentid,sql) ;//查询父ID,把该层查询到的数据都存放到resultset里面,因为我们查询的父ID是0,所以第一次运行时查询出的是最顶层   try{   while(rs.next()){  // System.out.println(rs.getString(3)) ;   parentid = rs.getInt(1) ;//此处是关键,把获取到的数据的ID存到parentid中,那么下面递归的时候就会查询出该记录是否有子分类了   String str = "|___ " ;   for(int i=0;i<level;i++){//判断level,每加一级就多一个...,这样显示出层次感     str=" . . . "+str ;   }   System.out.println(str+rs.getString(3));//输出结果   showTree(parentid,level+1,sql) ; //递归开始了,再次调用自身方法   }    }catch(Exception e){      }   }   public static void main(String args[])throws Exception{   String sql = "select * from news_class where newsclass_parentid=?" ;//自己定义sql,这样比较灵活,根据父ID查询出数据   Test tree = new Test() ;   tree.showTree(0, 0, sql) ;//为了演示,从父ID为0,也就是顶级分类开始查询   }}


输出结果为
|___ title1 . . . |___ title2 . . .  . . . |___ title5 . . .  . . . |___ title6 . . .  . . . |___ title7 . . .  . . . |___ title9 . . .  . . . |___ title10 . . .  . . .  . . . |___ title15 . . .  . . .  . . .  . . . |___ title18 . . .  . . .  . . .  . . .  . . . |___ 111111 . . .  . . . |___ title11 . . . |___ title3 . . . |___ title4 . . . |___ title16|___ title8|___ title12|___ title13|___ title14|___ title17|___ pc1



总结
1、ID和父ID之间的关系
从数据库和输出结果可以观察出,父ID为0的分类为顶级分类,之上再无父级
如title 1、8、12、13、14、17、pc1这几个都是顶级分类
而如title 2、3、4、16,他们的父ID为1,也就是title1的ID,则他们就是title1的子分类
而同时也有一些记录的父ID指定到title 2、3、4、16的ID上,所以title 2、3、4、16之中也有自己的子类
如title 2、10,上面有父级分类,下面也有子级分类

2、parentid = rs.getInt(1) ;
在showTree方法中,因为我们parentid初始值设定是0,所以第一次的结果获取到的应该是先把title1输出
然后接着parentid = rs.getInt(1),这句话就是说把title1的ID放到parentid里,title1的ID为1,所以这时候的parentid的值改变为1,这样下面的
showTree(parentid,level+1,sql) ;就会从parentid为1开始查询,查询title1的子分类,再把子分类的ID放到parentid里,又查询子分类的子子分类,以次类推下去,直到把所有的子类都查询出来为止。

个人认为递归是关键,理解好递归了才好做出来 1 楼 surelei 2011-06-23 如果我要取一个节点下的所有子孙节点,你如何读数据库?
当然可以cache在内存里用程序递归,但是如果数据量大呢?
一个无限级别的树,为了查询方便,一定需要id path,某些需求中还需要name path。 2 楼 burnquist 2011-06-24 我也只是做的简单练习

读书人网 >编程

热点推荐