1. 程式人生 > >資料庫中樹結構資料,轉換為Java物件樹結構( 多叉樹結構 )

資料庫中樹結構資料,轉換為Java物件樹結構( 多叉樹結構 )

總體就是圖所表示所表示的轉換,由資料庫 => Java物件轉換,程式碼比較簡單


提供了兩個查詢方法:

No.1 : Map<String,List<Tree>> arrMap = queryGroupToMap();//No.1(不推薦使用,執行時間較長)

No.1.1:Map<StringList<Tree>>arrMap=queryListToMap();//No.1.1(推薦使用,執行時間較短)

這個兩方法返回的Map內格式是一樣的.都是Map<String

List<Tree>> ,  key就是這組List<Tree>的父ID, value就是這組List


主要是物件之間建立關聯 No.2 : MapForTree(arrMap);


思路為: 用pid(父id)作分組 ,這樣每一個組的父節點是同一樣,換句話說就是同一分組裡,所有節點pid是相同的.這樣就針對分組操作,建立兩重關聯,子節點持有父節點物件,父節點持有子節點List. 就是說通過一個節點可以找得到自己的父節點與子節點


用Map做封裝,key為父ID, value為分組List

用到了QueryRunner

這個是資料庫工具,只要在網上找,下載就可以,能直接查詢List. 

QueryRunner jar包名=> commons-dbutils-1.5.jar 


 DTO程式碼:tree 類的程式碼.Javabean:

private String AREA_ID;	// 主鍵ID
	private String AREA_NAME;	// 用來顯示的名稱
	private String PARENT_ID;	// 父ID	參照AREA_ID
	private Tree parentObj;	// 父節點物件
	private List<Tree> childrenList = new ArrayList<Tree>();	// 子節點



執行程式碼:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;

/**
 * 資料庫中樹結構資料,轉換為Java物件樹結構( 多叉樹結構 )
 * @author liupengyuan
 *
 */
public class ListToTree {
	
	/**
	 * No.0:
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		long startTime=System.currentTimeMillis();   //獲取開始時間
		
		
		// 從資料庫中查詢所以分組的節點
//		Map<String, List<Tree>> arrMap = queryGroupToMap();	//No.1  (不推薦使用 執行時間較長)
		Map<String, List<Tree>> arrMap = queryListToMap();	//No.1.1  (推薦使用 執行時間較短)

		//	No.2:讓節點與子節點之間彼此關聯,並返回全有的根.(沒有父節點的都為根)
		List<Tree> rootTreeList = MapForTree(arrMap);

		//	從map裡把根找到.返回List . 可能有多個根
		List<Tree> list = arrMap.get("root");
		System.out.println(list.size());
		
		
		//獲取結束時間
		long endTime=System.currentTimeMillis();
		System.out.println("程式執行時間: "+(endTime-startTime)+"ms");
	}
	
	
	/**	
	 * No.1: 
	 * 通過多條sql查詢完成,資料庫壓力大( 不推薦使用 ).
	 * 用父ID分組,用Map封裝. key為父ID, value是所有父ID為KEY的節點陣列.
	 * 每個數組裡都是一組子節點,他們的根是同一個. 換句話說它們的父ID相同, 而Map的Key就是他們是父ID.
	 * @return
	 * @throws SQLException
	 */
	@SuppressWarnings({ "deprecation", "unchecked", "rawtypes" })
	public static Map<String,List<Tree>> queryGroupToMap() throws SQLException{
		
		/*
		 * 該表為中國地區組織,到 區縣級
		 * 比如,中國下分:北京市,河北省,山東省...
		 * 山東下分:濟南市,青島市,煙臺市...
		 * 
		 */
		
		// QueryRunner 這個是資料庫工具,只要在網上找下載就可以 commons-dbutils-1.5.jar
		QueryRunner qr = new QueryRunner();
		Connection connection = getJdbcConnection("jdbc:oracle:thin:@192.168.3.34:1521:ORCL", "DSD_ZJK", "DSD_ZJK", "oracle.jdbc.driver.OracleDriver");
		/*
		 * 用父Id分組查詢,找到所有的父ID
		 * 然後迴圈這個List查詢
		 */
		String sqlGroup = "select parent_id from  HM_F_AREA t group by t.parent_id";
		List<String> sqlGroupList = (List<String>)qr.query(connection, sqlGroup, new String[]{}, new ColumnListHandler("PARENT_ID"));

		Map<String,List<Tree>> arrMap = new HashMap<String,List<Tree>>(sqlGroupList.size());
		for(int i=0; i <sqlGroupList.size(); i++){
			String _pid = sqlGroupList.get(i);
			String sql = "select area_id , area_name , parent_id from  HM_F_AREA t where t.parent_id = '"+_pid + "'";
			List<Tree> listTree = (List<Tree>) qr.query(connection, sql, new String[]{} , new BeanListHandler(Tree.class));
			arrMap.put( _pid , listTree );
		}
		DbUtils.close(connection);
		return arrMap;
	}
	
	
	/**	
	 * No.1.1: 
	 * 通過兩條sql查詢完成.資料庫壓力較小些(推薦使用這個方法,執行的時間比 queryGroupToMap 短一半).
	 * 用父ID分組,用Map封裝. key為父ID, value是所有父ID為KEY的節點陣列.
	 * 每個數組裡都是一組子節點,他們的根是同一個. 換句話說它們的父ID相同, 而Map的Key就是他們是父ID.
	 * @return
	 * @throws SQLException
	 */
	@SuppressWarnings({ "unchecked", "deprecation", "rawtypes"})
	public static Map<String,List<Tree>> queryListToMap() throws SQLException{
		
		/*
		 * 該表為中國地區組織,到 區縣級
		 * 比如,中國下分:北京市,河北省,山東省...
		 * 山東下分:濟南市,青島市,煙臺市...
		 * 
		 */
		
		// QueryRunner 這個是資料庫工具,只要在網上找下載就可以 commons-dbutils-1.5.jar
		QueryRunner qr = new QueryRunner();
		Connection connection = getJdbcConnection("jdbc:oracle:thin:@192.168.3.34:1521:ORCL", "DSD_ZJK", "DSD_ZJK", "oracle.jdbc.driver.OracleDriver");
		
		//用父Id分組查詢,找到所有的父ID然後迴圈這個List查詢
		String sqlGroup = "select parent_id from  HM_F_AREA t group by t.parent_id";
		List<String> sqlGroupList = (List<String>)qr.query(connection, sqlGroup, new String[]{}, new ColumnListHandler("PARENT_ID"));

		//查詢出所有的節點
		Map<String,List<Tree>> arrMap = new HashMap<String,List<Tree>>(sqlGroupList.size());
		String sql = "select area_id , area_name , parent_id from  HM_F_AREA t ";
		List<Tree> listTree = (List<Tree>) qr.query(connection, sql, new String[]{} , new BeanListHandler(Tree.class));
		DbUtils.close(connection);
		
		
		/*
		 * 通過 父ID 和 所有的節點 比對
		 */
		for(int k=0;k<sqlGroupList.size();k++){
			String pid = sqlGroupList.get(k);
			
			List<Tree> tempTreeList = new ArrayList<Tree>();
			for(int i=0; i < listTree.size();i++){
				Tree tree = listTree.get(i);
				
				/*
				 * 將同一父ID的tree新增到同一個List中,最後將List放入Map..   arrMap.put(pid, tempTreeList);
				 * 這點雖然不復雜,但這是整個思索的中心,
				 */
				if(pid.equals(tree.getPARENT_ID())){
					tempTreeList.add(tree);
				}
			}
			
			// 最後將List放入Map..  key就是這組List<Tree>父ID, value就是這組List
			arrMap.put(pid, tempTreeList);
		}
		
		return arrMap;
	}
	
	
	/**
	 * No.2:
	 * 讓節點與子節點之間彼此關聯,並返回樹的根
	 * 資料庫格式並沒有換,只是建立了關聯
	 * @param arrMap
	 */
	public static List<Tree> MapForTree(Map<String, List<Tree>> arrMap){
		
		//所以pid的整合
		Set<String> pidSet = arrMap.keySet();
		
		//遍歷所有的父ID,然後與所以的節點比對,父id與id相同的    //找出對應的tree節點,然後將該節點的
		for (Iterator<String> it = pidSet.iterator(); it.hasNext();) {
			
    		String pid = (String) it.next();
    		
    		/*
    		 * 按分組的方式與pid比對.
    		 * 如果找到,那麼將該pid分組的List,做為子節點 賦值給該找到的節點的 setChildrenList(list),同時也將找到節點賦值List內所有子節點的parentObj
    		 * 
    		 */
        	for (Iterator<String> it2 = pidSet.iterator(); it2.hasNext();) {
        		
        		String key = (String) it2.next();
        		//不查詢自己的分組
        		if(pid.equals(key)){
        		//	break;
        		}
        		
        		List<Tree> list = arrMap.get(key);
        		
        		//	No.3:找出對應的tree父節點物件
        		Tree parentTree = indexOfList(list , pid);
        		
        		
        		if(parentTree!=null){
        			//通過pid在Map裡找出節點的子節點.
        			if("430000".equals(pid)){
        				System.out.println(pid);
        			}
        			List<Tree> childrenHereList = arrMap.get(pid);
        			
        			//TODO	這裡是我自己定義的變成成,都不一樣.所以需要自定義
        			// 把子節點List賦值給Tree節點的Children
        			parentTree.setChildrenList(childrenHereList);
            		
        			//TODO	這裡是我自己定義的變是,都不一樣.所以需要自定義
        			// 與上面相反,這是 把父節點物件賦值給Tree節點的parentObj
            		for(int i=0; i<childrenHereList.size(); i++){
            			Tree childrenHereTree = childrenHereList.get(i);
            			childrenHereTree.setParentObj(parentTree);
            		}
            	}
        	}
        }
		
		
		
    	// 找到 childrenHereTree.getParentObj(); 為null的就是根  return rootTreeList
		List<Tree> rootTreeList = new ArrayList<Tree>();
    	for (Iterator<String> it2 = pidSet.iterator(); it2.hasNext();) {
    		String key = (String) it2.next();
    		List<Tree> list = arrMap.get(key);
    		for(int i=0; i<list.size(); i++){
    			Tree tree = list.get(i);
    			if(null == tree.getParentObj()){
    				rootTreeList.add(tree);
    			}
    		}
    	}
		return rootTreeList;
		
	}
	
	
	
	/**
	 * No.3:
	 * 找出 list 中元素的id與pid相同的節點 的並返回.對應關係為: id與父id相同
	 * @param list
	 * @param pid
	 * @return
	 */
	public static Tree  indexOfList(List<Tree> list , String pid){
		for(int i=0 ;i<list.size();i++){
			Tree tree = list.get(i);
			/*
			 * pid:是 父ID
			 * area_id:是 ID
			 */
			//TODO	這裡是我自己定義的變成成,都不一樣.所以需要自定義
			if(pid.equals(tree.getAREA_ID())){
				return tree;
			}
		}
		return null;
	}
	
	/**
	 * 資料庫連線
	 * @param url
	 * @param username
	 * @param password
	 * @param driverClassName
	 * @return
	 */
	public static Connection getJdbcConnection(String url, String username, String password, String driverClassName){
		Connection connection = null;
		try {
			
			Properties props =new Properties();
			 
			props.put("user",username);
			props.put("password",password);
			props.put("remarksReporting","true");

			try {
				Class.forName(driverClassName).newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			connection=DriverManager.getConnection(url,props);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return connection;
		
	}
	
}