这几天研究多级树的设计,学到了点东西,分享一下心得:
表设计:
分组表(MasGroup)
- class MasGroup {
- String groupName
- boolean root = false
- static hasMany = [users: MasUser]
- static constraints = {
- }
- }
这里面特意增加了root属性,如果当前组是根元素的话,设置为true,主要是方便定位树根。
用户表(MasUser)
- class MasUser {
- String userName
- String mobileNumber
- static belongsTo = MasGroup
- static hasMany = [groups: MasGroup]
- static constraints = {
- }
- }
OK,由于每个组可以有多个子组,独立设计了树根组(GroupTree)
- class GroupTree {
- MasGroup currentGroup
- MasGroup childGroup
- static constraints = {
- }
- }
让Grails自动建表,分组信息会独立存放到group-tree表中。
下面是创建目录树的算法,之前琢磨了好久,用到节点深度、节点兄弟等好几种,刚刚开窍,思路是这样:
定位一个节点,先查找有没有子节点,有则创建ul树枝,然后递归循环孙子节点,没有则直接输出节点。
- class GroupTreeService {
- static transactional = true
- List<GroupTree> tree
- public String buildTreeMenu() {
- tree = GroupTree.findAll()
- if (tree == null || tree.isEmpty()) {
- System.out.println("uninitialized or no group tree defined")
- }
- // 查找根节点
- List<MasGroup> rootGroups = MasGroup.findAllByRoot(true)
- StringBuilder sb = new StringBuilder()
- sb.append("<ul id='navigation'>")
- rootGroups.each {
- sb.append(listTree(it))
- }
- sb.append("</ul>")
- return sb.toString()
- }
- /**
- * 列表树结构
- * @param mg 当前节点组
- * @return 该节点组的树结构
- */
- private String listTree(MasGroup mg) {
- // 寻找子节点
- List<MasGroup> children = this.findChildren(mg)
- StringBuilder sb = new StringBuilder()
- // 当前节点的子节点非空,循环子节点
- if (!children.isEmpty()) {
- // 先输出节点信息的树结构
- sb.append("<li><a>").append(mg.groupName).append("</a><ul>")
- // 循环节点
- children.each {
- // 节点还有子节点时,递归循环
- if (!this.findChildren(it).isEmpty())
- sb.append(this.listTree(it))
- else
- // 没有子节点,即末尾节点,输出节点信息
- sb.append("<li><a>").append(it.groupName).append("</a></li>")
- }
- // 结束节点树结构
- sb.append("</ul></li>")
- } else
- // 当前节点没有子节点,输出节点信息
- sb.append("<li><a>").append(mg.groupName).append("</a></li>")
- return sb.toString()
- }
- /**
- * 查找当前节点的子节点
- *
- * @param currentGroup 当前节点组
- * @return 子节点,如果没有,则返回空列表的集合(列表可能为空间,但集合一定非空)
- */
- private List<MasGroup> findChildren(MasGroup currentGroup) {
- List<MasGroup> children = new ArrayList<MasGroup>()
- tree.each {
- if (currentGroup.id == it.currentGroup.id)
- children.add(it.childGroup)
- }
- return children
- }
- }
这个跑起来之后,添加一些测试数据,能得到期望的结果,我使用了JQuery-treeview插件生成树目录,截图如下:
接下来做前台。