`
iorit2003
  • 浏览: 140858 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

树型结构列表

阅读更多
http://www.iteye.com/topic/189684

最近在自学RoR,看到了rainlife的帖子Rails生成Ext Tree,结合以前的Java项目经验,提出了我的一些想法。
以下的文字和rainlife的帖子Rails生成Ext Tree中我的回复大致相同,只是以SSH架构的Java代码重新实现了原帖中的内容。

我的疑问主要是在数据库的设计上,对于其中lft和rgt字段的设计感觉不好。当然我刚刚开始学习RoR,其中也许有很完备的解决方案我不知道,仅在此提出我的看法而以,如有异议,欢迎批评指正。
维护一个树型结构的类型列表,如下所示:
Root
    |- Child 1
    |    |- Child 1.1
    |    |- Child 1.2
    |- Child 2
        |- Child 2.1
        |- Child 2.2
原帖中表示树状节点的Category类中有lft和rgt这两个字段看上去是用来定义一个类型边界的。如果需要查找某个特定类型及其子类的话,则先查找该类型的lft和rgt,然后再 (lft > ? and rgt < ?) 获得其子类。
这种设计在数据结构完备的情况下能准确的统计出所有的子类。但是我要动态的增加Child子类,或者改变Child的隶属关系的时候,就需要对数据库表中所有数据的lft和rgt做出调整。比如我要在Child 1中增加一个Child 1.3。相应的 Root、Child 1、Child 2、Child 2.1、Child 2.2 的lft和rgt都要做相应的变化。
也许acts_as_nested_set可以通过先 delete from category; 后 insert into values(?,?,?,?); 的方式进行全类的维护,但是如果别的类有对Category的引用(即外键)。这样的隶属关系不是会产生混乱了吗?况且如果数据库真的建立了外键的话,也不允许 delete from category; 操作的。

所以我的考虑是用一个level字段代替lft和rgt字段,level字段维护着Category实例的层级关系。
例如,将root的level定义为1(这个在数据库或程序中可配),那么Child 1的level就为1|${id}(其中'|'为Level分层标记,${id}表示当前数据Id或其它可唯一标识的字段值),假定为1|2,同理Child 1.1的level就是1|2|3。
类结构如下所示:使用的是annotation的hibernate
Java代码
@Entity 
public class Category implements Serializable {  
 
    /** Level分层标记 */ 
    public static final String LEVEL_SPLIT = "|";  
 
    @Id 
    @GeneratedValue 
    private Integer id;  
      
    /** 名称 */ 
    private String name;  
 
    /** level */ 
    private String level;  
      
    /** 删除标记 */ 
    private Boolean delFlag;  
 
    /** 下级的类别 */ 
    @OneToMany(fetch = FetchType.LAZY, mappedBy="parent")  
    @OrderBy("id")  
    private List<Category> children = new ArrayList<Category>();  
 
    /** 上级的类别 */ 
    @ManyToOne 
    @JoinColumn(name = "category_id")  
    private Category parent;  
      
    // 省略所有 getter/setter 方法...  


@Entity
public class Category implements Serializable {

/** Level分层标记 */
public static final String LEVEL_SPLIT = "|";

@Id
@GeneratedValue
private Integer id;

/** 名称 */
private String name;

/** level */
private String level;

/** 删除标记 */
private Boolean delFlag;

/** 下级的类别 */
@OneToMany(fetch = FetchType.LAZY, mappedBy="parent")
@OrderBy("id")
private List<Category> children = new ArrayList<Category>();

/** 上级的类别 */
@ManyToOne
@JoinColumn(name = "category_id")
private Category parent;

// 省略所有 getter/setter 方法...
}

维护后数据库中的数据如下:



查找某个特定类型及其子类,只需要获得当前类型的level值,然后查找 (level like 'xxxx%')即可。如下所示:
Rails中需要重写Category中类似find的方法。
Java代码
public List<Category> getCategoryList(Integer startId) {  
    Category root = crudDao.get(Category.class, startId);   // crudDao继承HibernateDaoSupport,并封装了HibernateTemplate的操作,下同  
    String hql = "from Category where level like ? order by id desc";  
    return crudDao.query(hql, root.getLevel + Category.LEVEL_SPLIT + "%");  


public List<Category> getCategoryList(Integer startId) {
Category root = crudDao.get(Category.class, startId); // crudDao继承HibernateDaoSupport,并封装了HibernateTemplate的操作,下同
String hql = "from Category where level like ? order by id desc";
return crudDao.query(hql, root.getLevel + Category.LEVEL_SPLIT + "%");
}



新增或修改Category的方法。则需要先查找当前父类,再重新维护当前类的level属性值即可。如下所示:
Rails中需要重写Category中的add_child方法
Java代码
public void saveCategory(Category category) {  
    Category parent = category.getParent();  
    // 判断Category的父类有没有设置  
    if (parent == null || parent.getId() == null || parent.getId() == 0) {  
        throw new ParentNotFoundException(Category.class);   
    }  
    // 重新设置父类关系  
    parent = crudDao.get(Category.class, parent.getId());   // crudDao继承HibernateDaoSupport,并封装了HibernateTemplate的操作,下同  
    category.setParent(parent);  
      
    if (category.getId() == null || category.getId() == 0) {  
        crudDao.save(category);  
        category.setLevel(parent.getLevel() + Category.LEVEL_SPLIT + category.getId());  
        crudDao.update(category);  
    } else {  
        Category oldCategory = crudDao.get(Category.class, category.getId());  
        BeanUtils.copyProperties(category, oldCategory, new String[]{"id", "children"});  
        oldCategory.setLevel(parent.getLevel() + Category.LEVEL_SPLIT + oldCategory.getId());  
        crudDao.update(oldCategory);  
    }  


public void saveCategory(Category category) {
Category parent = category.getParent();
// 判断Category的父类有没有设置
if (parent == null || parent.getId() == null || parent.getId() == 0) {
throw new ParentNotFoundException(Category.class);
}
// 重新设置父类关系
parent = crudDao.get(Category.class, parent.getId()); // crudDao继承HibernateDaoSupport,并封装了HibernateTemplate的操作,下同
category.setParent(parent);

if (category.getId() == null || category.getId() == 0) {
crudDao.save(category);
category.setLevel(parent.getLevel() + Category.LEVEL_SPLIT + category.getId());
crudDao.update(category);
} else {
Category oldCategory = crudDao.get(Category.class, category.getId());
BeanUtils.copyProperties(category, oldCategory, new String[]{"id", "children"});
oldCategory.setLevel(parent.getLevel() + Category.LEVEL_SPLIT + oldCategory.getId());
crudDao.update(oldCategory);
}
}

使用Rails的ActiveRecord,以上代码可以写的更简练


页面显示,我使用的是纯javascript的dtree。代码如下所示:
Html代码
<body class="dtree"> 
<p><a href="javascript:categoryTree.openAll();">open all</a> | <a href="javascript:categoryTree.closeAll();">close all</a></p> 
<script type="text/javascript"> 
    var dtreeImgPath = "${ctx}/script/dtree/img/";  
    categoryTree = new dTree('categoryTree');  
    <c:forEach var="category" items="${list}"> 
    <c:choose> 
        <c:when test="${category.parent == null or category.parent == null or category.parent.id == 0}"> 
            categoryTree.add(${category.id},-1,'${category.name }',"javascript:doSelect('${category.id}','${category.name }')");  
        </c:when> 
        <c:otherwise> 
            categoryTree.add(${category.id},${category.parent.id},'${category.name }',"javascript:doSelect('${category.id}','${category.name }')");  
        </c:otherwise> 
    </c:choose> 
    </c:forEach> 
    document.write(categoryTree);  
</script> 
</body> 

<body class="dtree">
<p><a href="javascript:categoryTree.openAll();">open all</a> | <a href="javascript:categoryTree.closeAll();">close all</a></p>
<script type="text/javascript">
var dtreeImgPath = "${ctx}/script/dtree/img/";
categoryTree = new dTree('categoryTree');
<c:forEach var="category" items="${list}">
<c:choose>
<c:when test="${category.parent == null or category.parent == null or category.parent.id == 0}">
categoryTree.add(${category.id},-1,'${category.name }',"javascript:doSelect('${category.id}','${category.name }')");
</c:when>
<c:otherwise>
categoryTree.add(${category.id},${category.parent.id},'${category.name }',"javascript:doSelect('${category.id}','${category.name }')");
</c:otherwise>
</c:choose>
</c:forEach>
document.write(categoryTree);
</script>
</body>

原帖中是用Ext来实现视图的现实。我只需要在Struts2中使用JSONUtils实现一个Result,使得Action返回一个JSON对象,就可以在JSP中用Ext来显示树型结构的列表

显示的效果如下:


描述: Category 数据图
大小: 14 KB
查看次数: 5

描述: Category 显示效果图
大小: 9.1 KB
查看次数: 5
分享到:
评论

相关推荐

    js做的树型结构javascript作的树型结构javascript作的树型结构

    js做的树型结构,应该是很好的,javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型...

    教你如何用java开发树型结构

    2. **Java实现树型结构**:在Java中,我们可以使用类来表示树的节点,通常包括一个值字段和一个子节点列表。例如,`TreeNode`类可以包含一个`Object`类型的值和一个`ArrayList&lt;TreeNode&gt;`类型的子节点列表。为了支持...

    java递归树型结构通用数据库

    "Java递归树型结构通用数据库" Java递归树型结构通用数据库是指使用Java语言实现的递归树型结构数据库系统,该系统可以实现树型结构的部门管理,包括部门的添加、删除、修改和查询等操作。 知识点: 1. 递归树型...

    pb9 datawindow treeview 树型结构

    在本案例中,我们将探讨如何使用DataWindow来实现一个treeview,即树型结构,这对于组织层次化数据非常有用。TreeView控件在用户界面设计中常见,因为它提供了一种直观的方式来展示具有父子关系的数据。 1. **...

    一种基于Ajax的动态树型结构的设计与实现.pdf

    ### 一种基于Ajax的动态树型结构的设计与实现 #### 摘要 本文提出了一种新型的动态树型结构的实现方案,该方案利用了Yahoo用户界面库和Ajax(异步JavaScript和XML)技术。这种方法能够构建出结构清晰、具有良好...

    树型结构算法

    树型结构算法树型结构算法树型结构算法树型结构算法

    js动态树型结构 树型菜单

    树型结构和树型菜单是数据可视化的一种常见方式,它们能够帮助用户有效地组织和导航复杂的数据层次。在这个场景下,"js动态树型结构 树型菜单"指的是使用JavaScript实现的可以动态加载、展示和操作的树状菜单系统。 ...

    Delphi中数据库关联树型结构生成与同步数据维护.zip_数据同步_数据库关联_数据维护_树型结构生成

    在Delphi编程环境中,数据库关联树型结构的生成与同步数据维护是开发高效数据库应用程序的重要环节。本资料主要探讨了如何在Windows XP操作系统下,利用Delphi 7进行相关操作。 首先,我们要理解数据库关联的概念。...

    JSP实现树型结构TREE

    在IT行业中,构建树型结构的数据展示是一种常见的需求,特别是在Web应用中,用户界面往往需要以层次化的形式展示数据。本例"JSP实现树型结构TREE"提供了一个使用JSP(JavaServer Pages)、EXTJS(一个前端JavaScript...

    简单js树型结构好用

    在网页开发中,树型结构是一种常见的数据展示方式,它能有效地组织和展现层次化的信息。JavaScript(简称js)作为一种广泛使用的客户端脚本语言,常用于实现动态交互效果,包括构建树形结构。本篇文章将深入探讨如何...

    树型结构(javascript+css+html)

    下面将详细阐述如何使用这三种技术来实现树型结构。 一、HTML基础 HTML(HyperText Markup Language)主要用于构建网页的基本结构。在创建树型结构时,我们通常使用`&lt;ul&gt;`和`&lt;li&gt;`元素来代表树的节点和子节点。例如...

    vc++树型列表控件

    2. **自定义消息处理**:重载OnDrawItem和OnMeasureItem等消息处理函数,以便在绘制列表项时实现树型结构的视觉效果,如使用缩进表示层级,使用加减号图标表示可展开和折叠。 3. **数据存储**:维护一个数据结构来...

    winform树型结构

    树型结构(TreeView)是WinForm中常见的一种控件,它用于显示层次化的数据,通常表现为节点和子节点的形式,类似于计算机文件系统的目录结构。对于初学者来说,理解和掌握如何在WinForm中使用树型控件是非常重要的...

    JS生成树型结构

    在JavaScript(JS)编程中,生成树型结构是一种常见的需求,尤其在数据可视化、文件系统模拟、目录结构展示以及组织复杂的数据关系时。本篇将深入探讨如何利用JavaScript实现这样的功能,结合简单、易用且美观的代码...

    树型结构的存储文件 VB源码

    在IT领域,树型结构是一种常见的数据组织方式,它模拟了自然界中的树状关系,具有层级分明、易于查找和管理的特点。VB(Visual Basic)是微软公司开发的一种面向对象的编程语言,它提供了丰富的控件和函数库,使得...

    ROOT树型结构(JSP)

    "ROOT树型结构"通常指的是在Web应用中用于组织和展示数据的一种图形化方式,特别是对于层次结构明显的数据,如目录、组织架构或文件系统等。这种结构以树状的形式呈现,用户可以通过展开和折叠节点来探索和操作数据...

    网页树型结构快速加载大数据量数据的实现

    利用树型结构进行数据组织, 层次清晰、操作方便、用途广泛。介绍了一种基于 VS.NET 技术设计实现的大数据量树型结 构数据的快速加载方法, 通过一种改进的基于广度优先的算法, 将树型数据按照一定的层次和需要, 分散...

    js+html+xml树型结构非常棒

    在网页开发中,树型结构是一种常见的数据展示方式,它能清晰地呈现层次关系,使得信息组织更加有序。本文将详细探讨"js+html+xml树型结构"在Web开发中的应用,以及如何利用这些技术创建出高效且直观的树形展示。 ...

    delphi 树型控件自动根据数据集生成树型结构

    本文将详细讲解如何在 Delphi7 中使用树型控件,并自动根据数据集生成树型结构。 首先,理解 TTreeView 控件的基本操作。TTreeView 提供了一个可视化的组件,用于展示具有父节点和子节点的关系的数据。每个节点表示...

    我的树型结构练习使用

    在IT领域,树型结构是一种重要的数据结构,它在计算机科学中扮演着核心角色,尤其在算法和数据存储方面。树形结构模拟了自然界中的层级关系,非常适合表示具有层次性的数据,例如文件系统、组织结构、网页链接等。在...

Global site tag (gtag.js) - Google Analytics