對于java的樹形結構的抽象與拓展
近來幾日,在學習hibernate,在做練習的時候,想做一個樹形結構出來,比如組織架構,于是開始動手去嘗試,首先是利用hibernate自己的方式做一棵樹,于是開始動手構建persisten object,代碼如下:
- package com.zq.po;
- import javax.persistence.*;
- import java.util.List;
- @Entity
- @Table(name = "t_modual")
- public class Modual2 {
- private long dbid;
- private String nane;
- private String url;
- private Modual2 parent;
- private List<Modual2> children;
- public Modual2() {
- }
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- public long getDbid() {
- return dbid;
- }
- public void setDbid(long dbid) {
- this.dbid = dbid;
- }
- public String getNane() {
- return nane;
- }
- public void setNane(String nane) {
- this.nane = nane;
- }
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- @ManyToOne
- @JoinColumn(name = "parent_id")
- public Modual2 getParent() {
- return parent;
- }
- public void setParent(Modual2 parent) {
- this.parent = parent;
- }
- @OneToMany(mappedBy = "parent",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
- public List<Modual2> getChildren() {
- return children;
- }
- public void setChildren(List<Modual2> children) {
- this.children = children;
- }
- }
然后利用代碼聲生成結構,但是這樣一來,生成的表中,parent_id是強制關聯自己表的主鍵的,感覺這樣不是很靈活,于是就想著,把外鍵約束去掉,轉而在程序里控制好,這樣靈活性提高了。想想在工作中遇到的樹形結構的表設計中,也沒有加入外鍵約束,所以我就開始構建一個沒有外鍵約束的樹形結構。
經過思考,我決定使用如下的方式實現:抽象出一個BaseTree來,里面有主鍵,父親節點的ID,父親節點的對象和兒子節點的集合,這基本上是所有樹形結構都共有的特性,所以抽象出來,讓其他的樹去繼承,然后讓程序員更加關注本樹的業務字段。抽象出來的BaseTree代碼如下:
- package com.zq.po;
- import java.util.List;
- public class BaseTree<T> {
- private long dbid;
- private long parentId;
- private T parent;
- private List<T> children;
- public long getDbid() {
- return dbid;
- }
- public void setDbid(long dbid) {
- this.dbid = dbid;
- }
- public long getParentId() {
- return parentId;
- }
- public void setParentId(long parentId) {
- this.parentId = parentId;
- }
- public T getParent() {
- return parent;
- }
- public void setParent(T parent) {
- this.parent = parent;
- }
- public List<T> getChildren() {
- return children;
- }
- public void setChildren(List<T> children) {
- this.children = children;
- }
- }
然后再創建一棵樹,讓他繼承BaseTree,但是需要重寫主鍵和父節點ID這兩個屬性,因為需要把他們映射到數據庫里面去,代碼如下:
- package com.zq.po;
- import javax.persistence.*;
- import java.util.List;
- @Entity
- @Table(name="t_orga")
- public class Organization extends BaseTree<Organization>{
- private long dbid;
- private long parentId;
- private String name;
- private int count;
- //private Organization parent;
- //private List<Organization> children;
- public Organization() {
- }
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- public long getDbid() {
- return dbid;
- }
- public void setDbid(long dbid) {
- this.dbid = dbid;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getCount() {
- return count;
- }
- public void setCount(int count) {
- this.count = count;
- }
- public long getParentId() {
- return parentId;
- }
- public void setParentId(long parentId) {
- this.parentId = parentId;
- }
- /*@Transient
- public Organization getParent() {
- return parent;
- }
- public void setParent(Organization parent) {
- this.parent = parent;
- }
- @Transient
- public List<Organization> getChildren() {
- return children;
- }
- public void setChildren(List<Organization> children) {
- this.children = children;
- }*/
- }
這樣,模型就出來了,創建出來的表結構如下圖:完全沒有了外鍵約束符合要求:
雖然是模型和表都整出來了,但是有一個問題,當我們把所有的樹節點都查詢出來的時候,他們自身只有一個父節點的ID,想訪問他的父節點或者是孩子節點,需要拿著該節點的主鍵查孩子節點或者拿著patentId查父親節點,很是麻煩,于是就想著整一個工具類,把全查出來的節點的父親和兒子都匹配上,目前只是完成了全部節點的匹配,以后還會完成某一個節點的匹配。建了一個工具類,代碼如下:
- public class BaseTreeUtil extends BaseTree {
- private BaseTree baseTree1;
- private BaseTree baseTree2;
- public List allInit(List param) {
- //找老子
- for (int i = 0; i < param.size(); i++) {
- baseTree1 = (BaseTree) param.get(i);
- if (baseTree1.getParentId() == -1) {
- break;
- } else {
- for (int j = 0; j < param.size(); j++) {
- baseTree2 = (BaseTree) param.get(j);
- if (baseTree2.getDbid() == baseTree1.getParentId()) {
- baseTree2.setParent(baseTree1);
- }
- }
- }
- }
- //找兒子
- for (int k = 0; k < param.size(); k++) {
- baseTree1 = (BaseTree) param.get(k);
- List<BaseTree> sons = new ArrayList<BaseTree>();
- for (int l = 0; l < param.size(); l++) {
- baseTree2 = (BaseTree) param.get(l);
- if (baseTree1.getDbid() == baseTree2.getParentId()) {
- sons.add(baseTree2);
- }
- }
- baseTree1.setChildren(sons);
- }
- return param;
- }
- }
這樣就是把查出來的節點做循環,先是給每個節點的找到父親節點,然后在給每個節點去找兒子節點。
附上一段測試代碼(片段):
- public static void print(Organization orga, int level) {
- String show = "";
- for (int i = 0; i < level; i++) {
- show += "----";
- }
- System.out.println(show + orga.getName());
- level++;
- for (Organization children : orga.getChildren()) {
- print(children, level);
- }
- }
- @Test
- public void testSelect02() {
- Session session = this.before();
- Transaction tx = session.beginTransaction();
- Query query =session.createQuery("from Organization ");
- List<Organization> list=query.list();
- List list2= new BaseTreeUtil().allInit(list);
- print((Organization)list2.get(0), 0);
- this.after(tx);
- }
不好意思,忘記附上表的數據了,補上:
最后測試的結果如下:
到此,基本的功能都已經實現了,剩下需要做的有如下幾個:
1、晚上BaseTreeUtil的功能
2、把以上內容應用到DAO層的編寫中,整合到spring進行測試
后續工作的總結寫在下次日志中。
原文鏈接:http://www.software8.co/wzjs/java/3335.html