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

文章作者 100test 发表时间 2007:04:06 22:07:03
来源 100Test.Com百考试题网


在系统中,经常会用到无限级的树形结构分类,如组织机构管理、商品/地区分类等等。一般无外采用两种方式:

  一是类似struts-menu(http://struts-menu.sourceforge.net)的XML文件管理方式,配置起来比较方便,但很难与系统中其它应用数据集成;

  二是使用数据库存储,定义父子关系。

  在我们现在开发的一个产品中,使用hibernate实现了一套树形结构的处理方法,简介如下:

  ■演示地址:http://219.143.69.2:8000/treetest/menumanage.do?todoaction=list

  演示的是系统菜单的层次实现。由于菜单本身属于权限系统的一部分,存储在数据库中后可以方便的与部门、用户、岗位、职务等进行关联,并进行权限控制。

  ■树形结构显示,使用的是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 代码

  1. /**
  2. * 实现了树的基本操作,上溯、下溯、子节点的添加/移除和递归查找、对象关联等
  3. */
  4. package test.testtree.base.
  5. import java.util.Set.
  6. public interface Tree {
  7. public String getCode().
  8. public String getName().
  9. public String getDescription().
  10. public Tree getParent().
  11. public boolean isRoot().
  12. public boolean isLeaf().
  13. public boolean isParentOf(Tree tree).
  14. public boolean isChildOf(Tree tree).
  15. public void addChild(Tree tree).
  16. public void rmChild(Tree tree).
  17. public Set getAllChildren().
  18. public Set getChildren().
  19. public Set getAllLeaves().
  20. public void addObject(Object obj).
  21. public void rmObject(Object obj).
  22. public Set getObjects().
  23. public Long getId().
  24. }

BaseTree.java代码

  1. package test.testtree.base.
  2. import java.util.*.
  3. public abstract class BaseTree extends BasePojo implements Tree{
  4. protected String code.
  5. protected String name.
  6. protected String description.
  7. protected BaseTree parent.
  8. protected Set children = new HashSet().
  9. protected Set objects = new HashSet().
  10. public void setCode(String code) {
  11. this.code = code.
  12. }
  13. abstract public String getCode().
  14. public void setName(String name) {
  15. this.name = name.
  16. }
  17. abstract public String getName().
  18. public void setDescription(String description) {
  19. this.description = description.
  20. }
  21. abstract public String getDescription().
  22. abstract public Tree getParent().
  23. public boolean isRoot() {
  24. return (getParent()==null).
  25. }
  26. public boolean isLeaf() {
  27. return (this.getChildren().size()==0).
  28. }
  29. public boolean isParentOf(Tree tree) {
  30. if (tree==null || ((BaseTree) tree).equals(this)) {
  31. /*如果对方为空*/
  32. return false.
  33. }else if(this.isLeaf()){
  34. /*如果自己为叶子,则返回FALSE*/
  35. return false.
  36. }else if(tree.isRoot()){
  37. /*如果对方为根,返回FALSE*/
  38. return false.
  39. }else{
  40. BaseTree bt = (BaseTree) (tree.getParent()).
  41. if (this.equals(bt)){
  42. /*如果对方的父节点是自己,则返回TRUE*/
  43. return true.
  44. }else{
  45. /*判断对方的父节点是否是自己的孩子,进行递归*/
  46. return isParentOf(bt).
  47. }
  48. }
  49. }
  50. public boolean isChildOf(Tree tree) {
  51. return (tree.isParentOf(this)).
  52. }
  53. public void addChild(Tree tree) {
  54. children.add(tree).
  55. }
  56. public void rmChild(Tree tree) {
  57. children.remove(tree).
  58. ((BaseTree) tree).setParent(null).
  59. }
  60. public Set getAllLeaves() {
  61. Set set_old = this.getAllChildren().
  62. Set set = new HashSet().
  63. set.addAll(set_old).
  64. Iterator itr = set_old.iterator().
  65. while(itr.hasNext()){
  66. BaseTree bt = (BaseTree) itr.next().
  67. if (! bt.isLeaf()){
  68. set.remove(bt).
  69. }
  70. }
  71. return set.
  72. }
  73. public Set getAllChildren() {
  74. Set set = new HashSet().
  75. Stack stack = new Stack().
  76. stack.push(this).
  77. while(!stack.empty()){
  78. BaseTree bt = (BaseTree) stack.pop().
  79. set.add(bt).
  80. Iterator itr = bt.getChildren().iterator().
  81. while(itr.hasNext()){
  82. BaseTree btchild = (BaseTree) itr.next().
  83. stack.push(btchild).
  84. }
  85. }
  86. set.remove(this).
  87. return set.
  88. }
  89. public List getMeAndListAllChildren() {
  90. List lst = new Vector().
  91. lst.add(this).
  92. Iterator itr = this.getChildren().iterator().
  93. while(itr.hasNext()){
  94. BaseTree bt = (BaseTree) itr.next().
  95. lst.addAll(bt.getMeAndListAllChildren()).
  96. }
  97. return lst.
  98. }
  99. abstract public Set getChildren().
  100. public void addObject(Object obj) {
  101. objects.add(obj).
  102. }
  103. public void rmObject(Object obj) {
  104. objects.remove(obj).
  105. }
  106. abstract public Set getObjects().
  107. public void setParent(Tree parent) {
  108. this.parent = (BaseTree) parent.
  109. }
  110. public void setChildren(Set children) {
  111. this.children = children.
  112. }
  113. public void setObjects(Set objects) {
  114. this.objects = objects.
  115. }
  116. }


相关文章


HIbernate的参数使用说明
Hibernate编写通用数据库操作代码
开源技术—hiernate的锁机制
开源技术—hibernate点滴
使用hibernate实现树形结构无限级分类
Hibernate的继承关系
了解Hibernate的FlushMode.NEVER模式
在Hibernate中配置Proxool连接池
关于spring中的aop的解释
澳大利亚华人论坛
考好网
日本华人论坛
华人移民留学论坛
英国华人论坛