JavaEE專案實戰(OA系統)之十三_員工管理之一

hanhf發表於2016-09-17

  JavaEE專案實戰(OA系統)之十三_員工管理之一

  之前,我們已經完成了“部門管理”模組的練習,並初步掌握了ssh框架的程式設計。

  下面,我們再做一個練習即“員工管理”模組,通過這個練習,將進一步熟悉ssh框架。

  頁面一,員工列表:


  頁面二,員工新增/修改:



  “員工管理”模組重點解決幾個關鍵點,一是部門下拉選單的展示,二是員工列表中如何顯示部門名稱,三是新增/編輯頁面的展示細節。

  一、部門下拉選單的展示

  向資料庫中加入如下示例資料:

  部門表:


  員工表:



  1. SQL語句

  我們想讓部門下拉選單展示為:


  可是用普通的SQL語句,不管怎麼排序,是很難達到這個顯示順序的。

  幸好,Oracle資料庫針對樹形資料,提供了connect by語法。

  基本語法如下:

select * from tbl_dept
connect by prior dept_id=dept_p_id
start with dept_p_id=0;
  第一行是select,用於指定查詢內容。

  第二行是connect by,用於指定連線條件,connect by有點類似於自連線,指定當前記錄的一個欄位與上一條記錄的一個欄位連線。其中prior這個單詞表示“上一條記錄”,它的位置不同,會產生兩種效果:從根到葉和從葉到根。

  第三行是start with,用於指定起始條件,從樹的哪個位置開始。


  我們以scott使用者的emp表為例,emp(員工)表有empno(員工號)和mgr(上級領導的員工號),是典型的樹形資料。

  示例1:

select * from scott.emp
connect by prior mgr = empno
start with ename = 'SCOTT';
  查詢結果:


  這條語句可以這樣解釋,connect by prior mgr = empno,即使用上一條記錄的“上級領導的員工號”作為當前記錄的“員工號”,start with ename = 'SCOTT',表示起始點為名為SCOTT的員工。然後下一個員工,就使用上一條記錄的mgr欄位作為當前記錄的empno,產生的效果是從下級到上級。


  示例2:

select * from scott.emp
connect by prior empno = mgr
start with ename = 'KING';
  查詢結果:


  這條語句可以這樣解釋,connect by prior empno = mgr,即使用上一條記錄的“員工號”作為當前記錄的“上級領導的員工號”,start with ename = 'KING',表示起始點為名為KING的員工,KING是公司總裁。然後下一個員工,就使用上一條記錄的empno欄位作為當前記錄的mgr,產生的效果是從上級到下級。從上級到下級時,對樹的遍歷演算法使用先序遍歷,即先訪問根節點,再左樹,再右樹。


  回到我們的問題,通過下面的SQL語句可以實現目的:

select * from tbl_dept
connect by prior dept_id=dept_p_id
start with dept_p_id=0;

  其中,connect by prior dept_id=dept_p_id,會產生從上級到下級的效果,start with dept_p_id=0,符合條件的起始點會有多個,它們都是一級部門。

  查詢結果:



  2. DAO類

  修改一下介面,在介面中新增一個方法:

List<Dept2> getTree();

  這裡的Dept2,是一個自定義的實體類,程式碼如下:

public class Dept2 {
	private int id;
	private String name;
	private int level;

	// getter & setter
	// ...
}

  DAO類的程式碼如何編寫呢?首先,我們要清楚Hibernate的查詢有兩種,一種使用HQL(Hibernate Query Language,是Hibernate的查詢語言,功能很強大),它查詢的是實體類;另外,Hibernate也可以用原生的SQL。

  Hibernate進行HQL查詢時,使用Query物件:

		Session session = sessionFactory.getCurrentSession();
		Query query = session.createQuery("from Dept");
		return (List<Dept>) query.list();
  上述的connect by語法是Oracle特有的SQL語法,並沒有相應的HQL,屬於原生的SQL,需要使用Hibernate的SQLQuery物件。

  SQLQuery物件的list方法返回的資料一般是List<Object[]>,是值的陣列,不太方便,所以我們要將資料封裝成自定義實體的列表:

	public List<Dept2> getTree() {
		String sql = "select dept_id id, dept_name name, level from tbl_dept connect by prior dept_id=dept_p_id start with dept_p_id=0";
		Session session = sessionFactory.getCurrentSession();
		SQLQuery sqlQuery = session.createSQLQuery(sql);
		sqlQuery.addScalar("id", StandardBasicTypes.INTEGER);
		sqlQuery.addScalar("name", StandardBasicTypes.STRING);
		sqlQuery.addScalar("level", StandardBasicTypes.INTEGER);
		sqlQuery.setResultTransformer(Transformers
				.aliasToBean(Dept2.class));
		List<Dept2> list = (List<Dept2>) sqlQuery.list();
		return list;
	}

  在SQL語句中,為欄位取別名,別名與自定義實體類的屬性一致,然後呼叫addScalar方法一個個地新增欄位,最後呼叫轉換器將結果封裝成自定義實體的列表。

  至此,DAO類程式碼完成。


  3. Action類

  在員工管理的Action類中寫一個方法,對列表資料加以處理:

	private void getDeptTree() {
		deptList = deptBiz.getTree();
		for (Dept2 dept : deptList) {
			String name = dept.getName();
			if (dept.getLevel() > 1) {
				name = "└" + name;
			}
			for (int i = 1; i < dept.getLevel(); i++) {
				name = " " + name;
			}
			dept.setName(name);
		}
	}


  4. JSP頁面

  要將部門列表展示在下拉框中,JSP頁面使用如下程式碼:

請選擇部門: <select id="deptId" name="deptId">
			<option value="0">---請選擇部門---</option>
			<c:forEach items="${deptList}" var="dept">
				<option value="${dept.id}"
					<c:if test="${dept.id==deptId}">selected="selected"</c:if>>${dept.name}</option>
			</c:forEach>
		</select>

  最終完成的部門下拉選單的展示效果如下:



相關文章