使用hibernate实现树形结构无限级分类

转自 http://together.iteye.com/blog/29482?page=2

在系统中,经常会用到无限级的树形结构分类,如组织机构管理、商品/地区分类等等。在以前的一个贴子:http://www.iteye.com/topic/26987“复杂商品分类的表如何建立?”中,讨论过树形无级分类的实现方法。

一般无外采用两种方式,
  一是类似struts-menu(http://struts-menu.sourceforge.net)的XML文件管理方式,配置起来比较方便,但很难与系统中其它应用数据集成;
  二是使用数据库存储,定义父子关系。

在我们现在开发的一个产品中,使用hibernate实现了一套树形结构的处理方法,实现了树的基本操作,上溯、下溯、子节点的添加/移除和递归查找、对象关联等。简介如下:
适用范围,具有树形特征的所有对象,如树形菜单、组织结构、信息分类、论坛主贴与回复等。
完整源码下载(内置了hsql数据库及测试数据,正式使用时请将war置于APPSERVER的webapps目录下,修改解包后的WEB-INF/classes/hibernate.cfg.xml,编辑其中hsqldb的物理路径。如jdbc:hsqldb:file:c:\tomcat5\webapps\treetest\db\test)见附件,运行http://ServerName:ServerPort/treetest/menumanage.do。
树形结构显示,使用的是xtree。为便于编辑维护,自己写了一个左键弹出菜单(xtree的右键事件无法更改),进行节点的添加、修改、删除、转移操作。(PS:这套维护界面是完全跨浏览器的,有兴趣的不妨一试)
关联关系
可以使用objects对象来配置关联关系,实现多对多/一对多等关系。在BaseTree中,getObjects()方法是abstract的,可以根据需要自己定义。如论坛分类与每个分类所对应的贴子相关联,商品分类与商品编码相关联等,可以根据需要来处理hbm文件。若需要多项关联,亦可扩展。如菜单与用户、部门、岗位分别进行关联
hibernate2.1.7的一个bug,在这个测试源码的dao中,TreeManager的getRoots方法,
session.createQuery(" from " + cls.getName() + " where enabled=? and parent_id is null order by id");
在hibernate2中必须像写成parent_id is null,才能正确运行,这应该是2.1.7中的一个bug。而hibernate3中,可以使用parent is null的hsql。
主要代码
继承关系如下,假如要实现国家分类:
CountryTree extends BaseTree(abstract class)
          BaseTree(abstract class) implements Tree(interface)
为节省版面,下面代码去掉了javadoc
Tree.java

Java代码 复制代码
  1. /**
  2. *实现了树的基本操作,上溯、下溯、子节点的添加/移除和递归查找、对象关联等
  3. */
  4. packagetest.testtree.base;
  5. importjava.util.Set;
  6. publicinterfaceTree{
  7. publicStringgetCode();
  8. publicStringgetName();
  9. publicStringgetDescription();
  10. publicTreegetParent();
  11. publicSetgetParents();
  12. publicbooleanisRoot();
  13. publicbooleanisLeaf();
  14. publicbooleanisParentOf(Treetree);
  15. publicbooleanisChildOf(Treetree);
  16. publicvoidaddChild(Treetree);
  17. publicvoidrmChild(Treetree);
  18. publicSetgetAllChildren();
  19. publicSetgetChildren();
  20. publicSetgetAllLeaves();
  21. publicvoidaddObject(Objectobj);
  22. publicvoidrmObject(Objectobj);
  23. publicSetgetObjects();
  24. publicLonggetId();
  25. }



BaseTree.java

Java代码 复制代码
  1. packagetest.testtree.base;
  2. importjava.util.*;
  3. publicabstractclassBaseTreeextendsBasePojoimplementsTree{
  4. protectedStringcode;
  5. protectedStringname;
  6. protectedStringdescription;
  7. protectedBaseTreeparent;
  8. protectedSetchildren=newHashSet();
  9. protectedSetobjects=newHashSet();
  10. publicvoidsetCode(Stringcode){
  11. this.code=code;
  12. }
  13. abstractpublicStringgetCode();
  14. publicvoidsetName(Stringname){
  15. this.name=name;
  16. }
  17. abstractpublicStringgetName();
  18. publicvoidsetDescription(Stringdescription){
  19. this.description=description;
  20. }
  21. abstractpublicStringgetDescription();
  22. abstractpublicTreegetParent();
  23. publicbooleanisRoot(){
  24. return(getParent()==null);
  25. }
  26. publicbooleanisLeaf(){
  27. return(this.getChildren().size()==0);
  28. }
  29. publicbooleanisParentOf(Treetree){
  30. if(tree==null||((BaseTree)tree).equals(this)){
  31. /*如果对方为空*/
  32. returnfalse;
  33. }elseif(this.isLeaf()){
  34. /*如果自己为叶子,则返回FALSE*/
  35. returnfalse;
  36. }elseif(tree.isRoot()){
  37. /*如果对方为根,返回FALSE*/
  38. returnfalse;
  39. }else{
  40. BaseTreebt=(BaseTree)(tree.getParent());
  41. if(this.equals(bt)){
  42. /*如果对方的父节点是自己,则返回TRUE*/
  43. returntrue;
  44. }else{
  45. /*判断对方的父节点是否是自己的孩子,进行递归*/
  46. returnisParentOf(bt);
  47. }
  48. }
  49. }
  50. publicbooleanisChildOf(Treetree){
  51. return(tree.isParentOf(this));
  52. }
  53. publicvoidaddChild(Treetree){
  54. children.add(tree);
  55. }
  56. publicvoidrmChild(Treetree){
  57. children.remove(tree);
  58. ((BaseTree)tree).setParent(null);
  59. }
  60. publicSetgetAllLeaves(){
  61. Setset_old=this.getAllChildren();
  62. Setset=newHashSet();
  63. set.addAll(set_old);
  64. Iteratoritr=set_old.iterator();
  65. while(itr.hasNext()){
  66. BaseTreebt=(BaseTree)itr.next();
  67. if(!bt.isLeaf()){
  68. set.remove(bt);
  69. }
  70. }
  71. returnset;
  72. }
  73. publicSetgetParents(){
  74. Setparents=newHashSet();
  75. Treep=this.getParent();
  76. if(p!=null){
  77. parents.add(p);
  78. parents.addAll(p.getParents());
  79. }
  80. returnparents;
  81. }
  82. publicSetgetAllChildren(){
  83. Setset=newHashSet();
  84. Stackstack=newStack();
  85. stack.push(this);
  86. while(!stack.empty()){
  87. BaseTreebt=(BaseTree)stack.pop();
  88. set.add(bt);
  89. Iteratoritr=bt.getChildren().iterator();
  90. while(itr.hasNext()){
  91. BaseTreebtchild=(BaseTree)itr.next();
  92. stack.push(btchild);
  93. }
  94. }
  95. set.remove(this);
  96. returnset;
  97. }
  98. abstractpublicSetgetChildren();
  99. publicvoidaddObject(Objectobj){
  100. objects.add(obj);
  101. }
  102. publicvoidrmObject(Objectobj){
  103. objects.remove(obj);
  104. }
  105. abstractpublicSetgetObjects();
  106. publicvoidsetParent(Treeparent){
  107. this.parent=(BaseTree)parent;
  108. }
  109. publicvoidsetChildren(Setchildren){
  110. this.children=children;
  111. }
  112. publicvoidsetObjects(Setobjects){
  113. this.objects=objects;
  114. }
  115. }

你可能感兴趣的:(数据结构,Hibernate,struts,配置管理,HSQLDB)