最近在自学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
@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的方法。
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方法
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。代码如下所示:
<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
- 描述: Category 显示效果图
- 大小: 9.1 KB
分享到:
相关推荐
js做的树型结构,应该是很好的,javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型结构javascript作的树型...
本例是用JSP+EXTJS+JSON+MYQL实现的树型结构,例子结构清晰,便于学习。
Java递归树型结构通用数据库是指使用Java语言实现的递归树型结构数据库系统,该系统可以实现树型结构的部门管理,包括部门的添加、删除、修改和查询等操作。 知识点: 1. 递归树型结构数据库设计 在Java递归树型...
JavaScript树\利用JavaScript实现树型结构的TreeView类JavaScript树\利用JavaScript实现树型结构的TreeView类JavaScript树\利用JavaScript实现树型结构的TreeView类JavaScript树\利用JavaScript实现树型结构的...
使用js+div+span实现树型结构 非常简单的代码 一看就懂 下载解压直接打开就可以看出效果
pb9 用datawindow 实现 treeview 树型结构
我的树型结构练习使用我的树型结构练习使用我的树型结构练习使用我的树型结构练习使用
构数据的快速加载方法, 通过一种改进的基于广度优先的算法, 将树型数据按照一定的层次和需要, 分散地加载于树型结构上, 从 而较好地解决了大数量的树型数据在网页上树型结构加载时效率低下、延迟较长的问题。该方法...
一种基于Ajax的动态树型结构的设计与实现.pdf
树型结构算法树型结构算法树型结构算法树型结构算法
C_实现树型结构TreeView节点拖拽的简单功能,附全部源码,供有需要的参考
TreeView 是以类似于在Windows资源管理器左窗格中显示文件和文件夹的方式显示节点的层次结构。每个节点可能包含称为子节点的其他节点。父节点活包含子节点的节点能以展开活折叠的方式显示。TreeView用于显示按照树形...
javascript作的树型结构javascript作的树型结构javascript作的树型结构
NULL 博文链接:https://zouwu85.iteye.com/blog/778213
该组件应用java实现TreeView树型结构组件-源代码
delphi7 树型控件 自动根据数据集生成树型结构
asp实现树型结构
Jquery的treeTable实现树型结构显示数据,里面有官方Demo以及我写的一个Demo便于理解,希望对你们有所帮助
强大的HTML树结构代码 JavaScript实现树型结构特效
树型结构通用实现方法示例