Day03處理上級部門(樹狀結構)和用戶管理

  1. 系統管理:部門管理-處理上級部門

    添加或者修改時,上級部門的格式如圖:.解決此功能將面臨兩個問題:1.將全部部門名稱如下拉選的形式展現出來2.以樹狀結構展現.在此咱們先解決問題1.javascript

  1. 在添加頁面中展現全部部門名稱,並完成添加功能

    DepartmentAction:css

public String addUI() throws Exception { html

        //準備數據java

        List<Department> departmentList = departmentService.findAll(); jquery

        ActionContext.getContext().put("departmentList", departmentList); web

        

        return "saveUI"; spring

    }sql

SaveUI:(如下拉選形式展現全部部門名稱)數據庫

<tr><td width="100">上級部門</td> apache

<td>

    <s:select name="parentId" cssClass="SelectStyle"

        list="departmentList" listKey="id" listValue="name"

        headerKey="" headerValue="==請選擇==">

</s:select>

</td>

</tr>

<tr><td>部門名稱</td>

<td><s:textfield name="name" cssClass="InputStyle"/> *</td>

</tr>

<tr><td>職能說明</td>

<td><s:textarea name="description" cssClass="TextareaStyle"/></td>

</tr>

listKey是要提交過去的值,listValue是要在頁面上展現的值.name是數據庫中對應的字段.(能夠這麼理解:listKey對應的值要賦值給name對應的字段,在此爲parentId=id)

如果在添加頁面選擇了上級部門,由於Deparent.java中只有parent對象,並無parentId屬性.(這裏parentId是上級部門和下級部門的外鍵,數據庫中有可是JavaBean中沒有)

因此模型驅動封裝不了頁面提交過來的parentId,這時候要利用屬性驅動:在Action中聲明變量,並提供get,set方法:

完成添加頁面後,要完成添加(上級部門)的功能:

DepartmentAction:

public String save() throws Exception {

        //處理上級部門

        Department parent = departmentService.getById(parentId);

        model.setParent(parent);

        

        departmentService.save(model);

        return "toList";

    }

本身作的時候,展現上級部門出現了問題,緣由是list.jsp沒修改好:

DepartmentAction:

public String list() throws Exception {

        List<Department> departmentList = departmentService.findAll();

        ActionContext.getContext().put("departmentList", departmentList);

        return "list";

    }

List.jsp:

<s:iterator value="departmentList">

    <tbody id="TableData" class="dataContainer" datakey="departmentList">

                <tr class="TableDetail1 template">

                    <td><s:property value="name"/>&nbsp;</td>

                    <td><s:property value="parent.name"/>&nbsp;</td>

                    <td><s:property value="description"/>&nbsp;</td>

                    <td><s:a action="department_delete?id=%{id}" onclick="return confirm('肯定要刪除麼?')">刪除</s:a>

                <s:a action="department_editUI?id=%{id}">修改</s:a><br/>

                    </td>

                </tr>

        </tbody>

</s:iterator>

 

如果在添加頁面上,未選擇上級部門(即此部門爲頂級部門),則程序會報錯:

由於如果未選擇上級部門,則表單會將headerKey=""提交過去,此時id爲空,因此對應的parentId字段爲空.headerKey="" headerValue="==請選擇=="

解決辦法:在BaseDaoImpl中的getById()加入對id的判斷:

BaseDaoImpl:

public T getById(Long id) {

        if(id == null){

            return null;

        }

        else{

            return (T) getSession().get(clazz, id);

        }

    }

  1. 完成修改頁面的數據回顯(顯示原來的上級部門名稱),並完成修改功能

    DepartmentAction:

public String editUI() throws Exception {

        //準備回顯的數據

        Department department = departmentService.getById(model.getId());

        ActionContext.getContext().getValueStack().push(department);

        if(department.getParent() != null){

            this.parentId = department.getParent().getId();

        }

        

        //處理上級部門

        List<Department> departmentList = departmentService.findAll();

        ActionContext.getContext().put("departmentList", departmentList);

        

        return "saveUI";

    }

SaveUI:

<tr><td width="100">上級部門</td>

<td>

    <s:select name="parentId" cssClass="SelectStyle"

        list="departmentList" listKey="id" listValue="name"

        headerKey="" headerValue="==請選擇==">

</s:select>

</td>

</tr>

<tr><td>部門名稱</td>

<td><s:textfield name="name" cssClass="InputStyle"/> *</td>

</tr>

<tr><td>職能說明</td>

<td><s:textarea name="description" cssClass="TextareaStyle"/></td>

</tr>

<S:…></S:…>自帶回顯功能,隱藏了value屬性,value等於對應屬性的值. (先從棧頂找對應屬性的值,找不到再去map中找對應key,因此action中最好將對應屬性push進棧頂)

<s:select name="parentId" ></s:select>在這裏,value=parentId,由於listValue=name,因此下拉選會回顯name.

完成修改頁面的回顯功能後,再完成修改功能:

DepartmentAction:

    public String edit() throws Exception {

        //獲取要修改的數據庫中的原始數據

        Department department = departmentService.getById(model.getId());

        //修改

        department.setName(model.getName());

        department.setDescription(model.getDescription());

        department.setParent(departmentService.getById(parentId));

        //修改數據庫中的數據

        departmentService.update(department);

        return "toList";

    }

}

  1. 部門的級聯刪除,列表頁面默認顯示頂級部門列表,點擊部門名稱纔會看到其相應的子部門列表

    部門的級聯刪除(刪除一個部門時,其子部門也會被刪除)(inverse 是否維護關係cascade 級聯)

    想要級聯刪除哪一個對象,就要在那個對象的映射文件中寫上…如這裏要級聯刪除子部門,

<!-- children屬性,表達的是本對象與Department(下級)的一對多 -->

<set name="children" cascade="delete">

    <key column="parentId"></key>

    <one-to-many class="Department"/>

</set>

列表頁面默認顯示頂級部門列表,點擊部門名稱纔會顯示相應子部門列表:

DepartmentAction:

    /**

     * 列表:列表頁面只顯示一層的(同級的)部門數據,默認顯示最頂級的部門列表。

     */

    public String list() throws Exception {

        List<Department> departmentList = null;

        if(parentId == null){//默認顯示頂級部門列表

            departmentList = departmentService.findTopList();

        }else{    //顯示指定部門的子部門列表

            departmentList = departmentService.findChildren(parentId);

        }

        ActionContext.getContext().put("departmentList", departmentList);

        return "list";

    }

Ctrl+1在departmentService中建立方法,在departmentServiceImpl中實現方法(調用departmentDao中的方法)….

DepartmentDaoImpl:

    /**

     * 查找頂級部門列表

     */

    public List<Department> findTopList() {

        return getSession().createQuery(//

                "From Department d where d.parent.id IS NULL")//

                .list();

    }

 

    /**

     * 查找指定部門的子部門列表

     */

    public List<Department> findChildren(Long parentId) {

        return getSession().createQuery(//

                "From Department d where d.parent.id=?")//

                .setParameter(0, parentId)

                .list();

    }

List:

<!--顯示數據列表-->

        <s:iterator value="departmentList">

    <tbody id="TableData" class="dataContainer" datakey="departmentList">

                <tr class="TableDetail1 template">

                    <td>

                        <s:a action="department_list?parentId=%{id}">${name}</s:a>

                    </td>

                    <td><s:property value="parent.name"/>&nbsp;</td>

                    <td><s:property value="description"/>&nbsp;</td>

                    <td><s:a action="department_delete?id=%{id}" onclick="return confirm('肯定要刪除麼?')">刪除</s:a>

                <s:a action="department_editUI?id=%{id}">修改</s:a><br/>

                    </td>

                </tr>

        </tbody>

</s:iterator>

解析:列表頁面一開始默認顯示頂級部門列表,當在列表頁面點擊某個部門名稱後(parentId會被提交到DepartmentAction中的list方法中),列表頁面就會顯示相應的子部門列表了.

  1. 從列表轉到添加頁面時,默認選中原列表的上級部門;增長"返回上一級"的功能;添加,修改,刪除成功後還轉到原列表頁面,而不是頂級列表頁面,解決懶加載的問題

    從列表轉到添加頁面時,下拉選默認顯示原列表的上級部門名稱:

    DepartmentAction:

    public String list() throws Exception {

        List<Department> departmentList = null;

        if(parentId == null){//默認顯示頂級部門列表

            departmentList = departmentService.findTopList();

        }else{    //顯示指定部門的子部門列表

            departmentList = departmentService.findChildren(parentId);

            Department parent = departmentService.getById(parentId);

            ActionContext.getContext().put("parent", parent);

        }

        ActionContext.getContext().put("departmentList", departmentList);

        return "list";

    }

 

    public String addUI() throws Exception {

        //準備數據

        List<Department> departmentList = departmentService.findAll();

        ActionContext.getContext().put("departmentList", departmentList);

        return "saveUI";

    }

解析:這裏departmentService.getById(parentId)有parentId,是由於list中的<s:a action="department_list?parentId=%{id}">${name}</s:a>.在列表頁面每點擊一個部門名稱,就會傳遞parentId到Action中的list()方法從新查詢列表.

如果沒有parentmentId,則說明是頂級列表.

List:

        <!--顯示數據列表-->

        <s:iterator value="departmentList">

    <tbody id="TableData" class="dataContainer" datakey="departmentList">

                <tr class="TableDetail1 template">

                    <td>

                        <s:a action="department_list?parentId=%{id}">${name}</s:a>

                    </td>

                    <td><s:property value="parent.name"/>&nbsp;</td>

                    <td><s:property value="description"/>&nbsp;</td>

                    <td><s:a action="department_delete?id=%{id}" onclick="return confirm('肯定要刪除麼?')">刪除</s:a>

                <s:a action="department_editUI?id=%{id}">修改</s:a><br/>

                    </td>

                </tr>

        </tbody>

</s:iterator>

</table>

 

<!-- 其餘功能超連接 -->

<div id="TableTail">

<div id="TableTail_inside">

<s:a action="department_addUI?parentId=%{ #parent.id }">

<img src="${pageContext.request.contextPath}/style/images/createNew.png" />

</s:a>

</div>

</div>

解析:<s:a action="department_addUI?parentId=%{ #parent.id }">不寫#的話,會先從棧頂找,此時Action中的model(Deaprtment)真的有值,但model的parent值爲空,因此會用這個空值.加上#的話,會直接從map中找.(在action中已經將parent put進map)

SaveUI:

<tr><td width="100">上級部門</td>

<td>

    <s:select name="parentId" cssClass="SelectStyle"

        list="departmentList" listKey="id" listValue="name"

        headerKey="" headerValue="==請選擇==">

</s:select>

</td>

</tr>

解析:要讓saveUI的下拉選中回顯原上級部門名稱,關鍵就是要讓Action中有parentId(此時在Action中是用屬性驅動的方式封裝parentId的).由於<s:select name="parentId"…/>會先去棧頂找parentId,而此時在棧頂的是Action(由於在addUI中並無將什麼值push進棧頂),因此Action中的parentId天然會被找到.所以雖然Action中的addUI()方法並無什麼改變(沒有特地去接收list傳遞過來的parentId),可是saveUI中<s:select name="parentId"…/>仍是能夠獲取到Action中的parentId.

注意: <s:a action="department_addUI?parentId=%{ #parent.id }">是將parentId傳遞給addUI(),這樣saveUI(addUI的返回值就是saveUI)才能拿到parentId.並非只要讓action中有parentId就好.

好比<s:a action="department_list?parentId=%{id}">${name}</s:a>就將parentId傳過來了,但他是將parentId傳遞給list(),而不是給addUI(),因此saveUI()拿不到這個parentId.

重點是要將值棧,map,何時有值,值何時有效弄明白.

增長返回上一級的功能:

打個比方,有一級,二級,三級三個部門.一級爲二級的上級部門,二級爲三級的上級部門.現處在三級,若想回到二級,由於二級的上級部門爲一級,因此得將二級的parentId設置爲一級的Id.即將parentId=parent.parentId.id傳遞過去.

DepartmentAction:

    public String list() throws Exception {

        List<Department> departmentList = null;

        if(parentId == null){//默認顯示頂級部門列表

            departmentList = departmentService.findTopList();

        }else{    //顯示指定部門的子部門列表

            departmentList = departmentService.findChildren(parentId);

            Department parent = departmentService.getById(parentId);

            ActionContext.getContext().put("parent", parent);

        }

        ActionContext.getContext().put("departmentList", departmentList);

        return "list";

    }

這裏departmentList是指定部門的子部門集合,而parent是那個指定的部門,在此的做用爲存儲id,便於賦值給parentId.雖然說他們的parentId都同樣,但departmentList的parentId並很差獲取,因此parent並很少餘.

List:

<!-- 其餘功能超連接 -->

<div id="TableTail">

<div id="TableTail_inside">

<s:a action="department_addUI?parentId=%{ #parent.id }">

<img src="${pageContext.request.contextPath}/style/images/createNew.png" />

</s:a>

<!-- 不是頂級部門時,才須要顯示'返回上一級'按鈕 -->

<s:if test="#parent != null">

     <s:a action="department_list?parentId=%{ #parent.parent.id }">返回上一級</s:a>

</s:if>

</div>

</div>

解析:不加#的話,會先從棧頂找,而此時棧頂是Action,Action的model(Department)中有parent,但爲空 (每一個Action都會有model屬性(模型驅動使然),但Action中的list()並無用到model(沒有什麼值被傳遞過來),因此model爲空),那麼他就會用空值.加了#以後,他會直接去map中找.

添加,修改,刪除後回到原列表頁面,而不是頂級列表頁面:

以前作完這些操做後都會回到頂級列表頁面,這是由於增刪改方法的返回值都是toList,而struts.xml中toList的跳轉代碼已經寫死了.

<result name="toList" type="redirectAction">department_list</result>

因此想要回到原列表頁面的話,就要修改Struts.xml:

<result name="toList" type="redirectAction">department_list?parentId=${parentId}</result>

他會回到Action中尋找parentId.

List:

        <!--顯示數據列表-->

        <s:iterator value="departmentList">

    <tbody id="TableData" class="dataContainer" datakey="departmentList">

                <tr class="TableDetail1 template">

                    <td>

                        <s:a action="department_list?parentId=%{id}">${name}</s:a>

                    </td>

                    <td><s:property value="parent.name"/>&nbsp;</td>

                    <td><s:property value="description"/>&nbsp;</td>

                    <td><s:a action="department_delete?id=%{id}&parentId=%{parent.id}" onclick="return confirm('肯定要刪除麼?')">刪除</s:a>

                <s:a action="department_editUI?id=%{id}">修改</s:a><br/>

                    </td>

                </tr>

        </tbody>

</s:iterator>

DepartmentAction:

    public String delete() throws Exception {

        departmentService.delete(model.getId());

        return "toList";

    }

因爲以前的刪除方法並無傳遞parentId,因此Struts.xml中的<result name="toList" type="redirectAction">department_list?parentId=${parentId}</result>

取不到parentId.

能夠在list中把parentId傳過去,由於它在循環語句中,迭代的變量departmentList中的parent不爲空,因此能夠直接取他的parent的id.因此不用加#.(被put進map的parent和departmentList的parent的id是同樣的)

解決懶加載的問題:

Web.xml:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

 

    <!-- Spring的用於初始化ApplicationContext對象的監聽器 -->

    <listener>

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:applicationContext*.xml</param-value>

    </context-param>

 

    <!-- 配置SpringOpenSessionInViewFilter以解決懶加載異常的問題 -->

    <filter>

        <filter-name>OpenSessionInViewFilter</filter-name>

        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>OpenSessionInViewFilter</filter-name>

        <url-pattern>*.do</url-pattern>

    </filter-mapping>

 

    <!-- 配置Struts2的核心的過濾器 -->

    <filter>

        <filter-name>struts2</filter-name>

        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>struts2</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

 

 

    <welcome-file-list>

        <welcome-file>index.jsp</welcome-file>

    </welcome-file-list>

</web-app>

注意:解決懶加載問題的代碼必定要放到Struts2的核心過濾器的前面,否則他不給放行.

  1. 展現樹狀結構.在選擇或修改上級部門時,上級部門列表中不能顯示當前修改的部門及其子孫部門。

    使用遞歸遍從來展現樹狀結構.

    遍歷部門數,把全部部門名稱都改掉後放到同一個list中返回,經過名稱中的空格(這裏是經過=)來表現層次

    DepartmentAction:

    public String addUI() throws Exception {

/*//準備數據

        List<Department> departmentList = departmentService.findAll();

ActionContext.getContext().put("departmentList", departmentList);*/

        

        //準備數據

        List<Department> topList = departmentService.findTopList();

        List<Department> departmentList = DepartmentUtils.getAllDepartmentList(topList);

        ActionContext.getContext().put("departmentList", departmentList);

        return "saveUI";

    }

 

    public String editUI() throws Exception {

        //準備回顯的數據

        Department department = departmentService.getById(model.getId());

        ActionContext.getContext().getValueStack().push(department);

        if(department.getParent() != null){

            this.parentId = department.getParent().getId();

        }

        

        /*//處理上級部門

        List<Department> departmentList = departmentService.findAll();

        ActionContext.getContext().put("departmentList", departmentList);*/

        

        //處理上級部門

        List<Department> topList = departmentService.findTopList();

        List<Department> departmentList = DepartmentUtils.getAllDepartmentList(topList);

        ActionContext.getContext().put("departmentList", departmentList);

        return "saveUI";

    }

 

DepartmentUtils:

public class DepartmentUtils {

    /**

     * 遍歷部門數,把全部部門名稱都改掉後放到同一個list中返回,經過名稱中的空格(這裏是經過=)來表現層次

     * @author Tan

     *

     */

    public static List<Department> getAllDepartmentList(List<Department> topList){

        List<Department> list = new ArrayList<Department>();

        walkTree(topList, "|-", list);

        return list;

    }

 

    //遞歸遍歷

    private static void walkTree(Collection<Department> topList, String prefix, List<Department> list) {

        for (Department top : topList) {

            //建立副本,不要修改session緩存中的對象,最好使用副本

            Department copy = new Department();

            copy.setId(top.getId());

            //頂點

            copy.setName(prefix + top.getName());

            list.add(copy);        //注意:添加的是copy對象

            //子樹

            walkTree(top.getChildren(), "="+prefix, list);//若是想使用空格來表現層次結構,就必須使用全角的空格,否則在html上只能顯示一個空格.

        }

    }

}

Tips: 1.不要修改session緩存中的對象,最好使用副本,如果不使用副本:

Session中有一級緩存機制,在調用DepartmentUtils時,由於DepartmentUtils中並無開事務,全部雖然在DepartmentUtils中修改了session緩存中的數據(改了部門名稱),可是卻不會將修改的數據更新到數據庫.但若以後又開了一個事務:

數據庫中的數據就會被更新.因此不要修改session緩存中的對象,最好使用副本,除非想要更新數據到數據庫.

2.若是想使用空格來表現層次結構,就必須使用全角的空格,否則在html上只能顯示一個空格.

 

上級部門列表中不能顯示當前修改的部門及其子孫部門。由於不能選擇自已或自已的子部門做爲上級部門。

DepartmentAction:

    public String addUI() throws Exception {

        /*//準備數據

        List<Department> departmentList = departmentService.findAll();

        ActionContext.getContext().put("departmentList", departmentList);*/        

        

        //準備數據

        List<Department> topList = departmentService.findTopList();

        List<Department> departmentList = DepartmentUtils.getAllDepartmentList(topList, null);

        ActionContext.getContext().put("departmentList", departmentList);

        return "saveUI";

    }

 

    public String editUI() throws Exception {

        //準備回顯的數據

        Department department = departmentService.getById(model.getId()); //當前要修改的部門

        ActionContext.getContext().getValueStack().push(department);

        if(department.getParent() != null){

            this.parentId = department.getParent().getId();

        }

        

        /*//處理上級部門

        List<Department> departmentList = departmentService.findAll();

        ActionContext.getContext().put("departmentList", departmentList);*/

        

        //處理上級部門

        List<Department> topList = departmentService.findTopList();

        List<Department> departmentList = DepartmentUtils.getAllDepartmentList(topList, department);

        ActionContext.getContext().put("departmentList", departmentList);

        return "saveUI";

    }

DepartmentUtils:

public class DepartmentUtils {

    /**

     * 遍歷部門數,把全部部門名稱都改掉後放到同一個list中返回,經過名稱中的空格(這裏是經過=)來表現層次

     * @param topList

     * @param removedDepartment

     *             這個部門和這個部門的子孫部門都不要,若是爲空,表示沒有要移除的部門分支

     * @author Tan

     *

     */

    public static List<Department> getAllDepartmentList(List<Department> topList, Department removedDepartment){

        List<Department> list = new ArrayList<Department>();

        walkTree(topList, "|-", list, removedDepartment);

        return list;

    }

 

    //遞歸遍歷

    private static void walkTree(Collection<Department> topList, String prefix, List<Department> list, Department removedDepartment) {

        for (Department top : topList) {

            //去掉指定部門的分支

            if(removedDepartment.getId() != null && top.getId().equals(removedDepartment.getId())){

                continue;

            }

            

            //建立副本,不要修改session緩存中的對象,最好使用副本

            Department copy = new Department();

            copy.setId(top.getId());

            //頂點

            copy.setName(prefix + top.getName());

            list.add(copy);        //注意:添加的是copy對象

            //子樹

            walkTree(top.getChildren(), "="+prefix, list, removedDepartment);//若是想使用空格來表現層次結構,就必須使用全角的空格,否則在html上只能顯示一個空格.

        }

    }

}

添加時沒有要移除的部門,因此能夠穿個null過去.Continue:結束這次循環,進行下一次的循環.

效果:在此,研發部>二級研發部>三級研發部,則在修改研發部的頁面上,上級部門下拉選中就不會出現二級和三級研發部,在修改二級研發部的頁面上,上級部門下拉選中就不會出現三級研發部.

6.一些改進

修改代碼模板(好比syso,讓代碼效率更高)

抽取BaseAction,其中聲明瞭service還提供了對ModelDriven的支持.之後其餘Action只要繼承他就行了,沒必要再聲明service和支持modeldriven.

BaseAction:

package cn.itcast.oa.base;

import java.lang.reflect.ParameterizedType;

import javax.annotation.Resource;

import cn.itcast.oa.service.DepartmentService;

import cn.itcast.oa.service.RoleService;

import com.opensymphony.xwork2.ActionSupport;

import com.opensymphony.xwork2.ModelDriven;

 

public class BaseAction<T> extends ActionSupport implements ModelDriven<T>{

 

    //------------聲明service------------

    @Resource

    protected DepartmentService departmentService;

    @Resource

    protected RoleService roleService;

 

    //------------ModelDriven的支持------------

    protected T model;

    

    public BaseAction() {

        //經過反射獲取T的真實類型

        try{

            ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();

            Class<T> clazz = (Class<T>) pt.getActualTypeArguments()[0];

            model = clazz.newInstance();

        }catch(Exception e){

            throw new RuntimeException(e);

        }

    }

    public T getModel() {

        return model;

    }    

}

其餘Action要作的修改,如DepartmentAction,只需繼承BaseAction,提供類型,並將對service的聲明和對modeldriven的支持刪除便可.

public class DepartmentAction extends BaseAction<Department>

 

抽取JSP頁面中的公共代碼:

Header.jspf:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="s" uri="/struts-tags"%>

 

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<script language="javascript" src="${pageContext.request.contextPath}/script/jquery.js"></script>

<script language="javascript" src="${pageContext.request.contextPath}/script/pageCommon.js" charset="utf-8"></script>

<script language="javascript" src="${pageContext.request.contextPath}/script/PageUtils.js" charset="utf-8"></script>

<link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/style/blue/pageCommon.css" />

 

<script type="text/javascript">

</script>

而後在其餘jsp中靜態包含Header.jspf

<%@ include file="/WEB-INF/jsp/public/header.jspf" %>

 

將service和dao合併:

首先將有關dao的測試代碼,Dao和DaoImpl包都刪除,其次將BaseDao和BaseDaoImpl分別更名爲DaoSupport和DaoSupportImpl,在DaoSupportImpl中開啓事務(在類上加@Transactional).

此時其餘service接口要繼承DaoSupport接口,須要刪掉service接口中的公共方法,可是非公共方法要保留.ServiceImpl要繼承DaoSupportImpl,刪除其中的公共方法,保留非公共的方法,再將原來相應DaoImpl中非公共方法的代碼拷貝過來.如:

DepartmentService:

public interface DepartmentService extends DaoSupport<Department>{

/*    *//**

     * 查詢全部

     *//*

    List<Department> findAll();

 

    *//**

     * 刪除

     *//*

    void delete(Long id);

 

    *//**

     * 添加

     *//*

    void save(Department model);

 

    *//**

     * 經過id查詢

     *//*

    Department getById(Long id);

 

    *//**

     * 修改

     *//*

    void update(Department department);

*/

    /**

     * 查找頂級部門列表

     */

    List<Department> findTopList();

 

    /**

     * 查找指定部門的子部門列表

     */

    List<Department> findChildren(Long parentId);

 

 

}

DepartmentServiceImpl:

@Service

@Transactional

@SuppressWarnings("unchecked")

public class DepartmentServiceImpl extends DaoSupportImpl<Department> implements DepartmentService {

 

/*    @Resource

    private DepartmentDao departmentDao;

    

    public List<Department> findAll() {

        return departmentDao.findAll();

    }

 

    *//**

     * 獲取對象

     *//*

    public Department getById(Long id) {

        return (Department) departmentDao.getById(id);

    }

 

    *//**

     * 刪除數據

     *//*

    public void delete(Long id) {

        departmentDao.delete(id);

    }

 

    *//**

     * 保存數據

     *//*

    public void save(Department model) {

        departmentDao.save(model);

    }

 

    *//**

     * 修改數據

     *//*

    public void update(Department department) {

        departmentDao.update(department);

    }

*/

    /**

     * 查找頂級部門列表

     */

    public List<Department> findTopList() {

        return getSession().createQuery(//

                "From Department d where d.parent.id IS NULL")//

                .list();

    }

 

    /**

     * 查找指定部門的子部門列表

     */

    public List<Department> findChildren(Long parentId) {

        return getSession().createQuery(//

                "From Department d where d.parent.id=?")//

                .setParameter(0, parentId)

                .list();

    }

}

Tips:必定要在DaoSupportImpl中開啓事務(在類上加@Transactional).

由於

@Transactional註解,當寫到類上時:

1,對本類中的公共方法有效。

2,對子類中的公共方法有效(即這個註解能夠被繼承)

3,對父類中的方法無效!!!

 

二.用戶管理,增刪改查

 

建立代碼模板crud(即增刪改查):

詳細代碼以下:

    /** 列表 */

    public String list() throws Exception {

          

        

 

        return "list";

    }

 

    /** 刪除 */

    public String delete() throws Exception {

          

        

 

        return "toList";

    }

 

    /** 添加頁面 */

    public String addUI() throws Exception {

          

        

 

        return "saveUI";

    }

 

    /** 添加 */

    public String add() throws Exception {

          

        

 

        return "toList";

    }

 

    /** 修改頁面 */

    public String editUI() throws Exception {

          

        

 

        return "saveUI";

    }

 

    /** 修改 */

    public String edit() throws Exception {

          

        

 

        return "toList";

    }

在UserServiceImpl類上寫不寫@Transactional均可以,由於DaoSupportImpl中已經開啓了事務管理.(由於@Transactional能夠被繼承)(不過最好寫,方便看)

附用戶管理源代碼:

UserAction:

package cn.itcast.oa.view.action;

 

import java.util.HashSet;

import java.util.List;

 

import org.apache.commons.codec.digest.DigestUtils;

import org.springframework.context.annotation.Scope;

import org.springframework.stereotype.Controller;

 

import com.opensymphony.xwork2.ActionContext;

 

import cn.itcast.oa.base.BaseAction;

import cn.itcast.oa.domain.Department;

import cn.itcast.oa.domain.Role;

import cn.itcast.oa.domain.User;

import cn.itcast.oa.util.DepartmentUtils;

 

@Controller

@Scope("prototype")

public class UserAction extends BaseAction<User>{

    

    private Long departmentId;

    private Long[] roleIds;

    

    /** 列表 */

    public String list() throws Exception {

 

        List<User> userList = userService.findAll();

        ActionContext.getContext().put("userList", userList);

        

        return "list";

    }

 

    /** 刪除 */

    public String delete() throws Exception {

 

        userService.delete(model.getId());

        

        return "toList";

    }

 

    /** 添加頁面 */

    public String addUI() throws Exception {

 

        //準備數據 >>departmentList

        List<Department> topList = departmentService.findTopList();

        List<Department> departmentList = DepartmentUtils.getAllDepartmentList(topList, null);

        ActionContext.getContext().put("departmentList", departmentList);

        

        //準備數據 >>roleList

        List<Role> roleList = roleService.findAll();

        ActionContext.getContext().put("roleList", roleList);

            

        return "saveUI";

    }

 

    /** 添加 */

    public String add() throws Exception {

        //封裝數據

        // >>處理關聯的一個部門

        model.setDepartment(departmentService.getById(departmentId));

        // >>處理關聯的多個崗位

        List<Role> roleList = roleService.getByIds(roleIds);

        model.setRoles(new HashSet<Role>(roleList));

        

        //保存到數據庫

        userService.save(model);

        return "toList";

    }

 

    /** 修改頁面 */

    public String editUI() throws Exception {

        //準備回顯的數據

        User user = userService.getById(model.getId());

        ActionContext.getContext().getValueStack().push(user);

        //處理部門

        if(user.getDepartment() != null){

            departmentId = user.getDepartment().getId();

        }

        //處理崗位

        roleIds = new Long[ user.getRoles().size() ];

        int index = 0;

        for (Role role : user.getRoles()) {

            roleIds[ index++ ] = role.getId();

        }

        

        //準備數據 >>departmentList

        List<Department> topList = departmentService.findTopList();

        //將用戶放到哪一個部門均可以,因此沒有要移除的部門

        List<Department> departmentList = DepartmentUtils.getAllDepartmentList(topList, null);

        ActionContext.getContext().put("departmentList", departmentList);

        

        //準備回顯的數據 >>roleList

        List<Role> roleList = roleService.findAll();

        ActionContext.getContext().put("roleList", roleList);

        

        return "saveUI";

    }

 

    /** 修改 */

    public String edit() throws Exception {

        //從數據庫中取出原對象

        User user = userService.getById(model.getId());

        

        //設置要修改的屬性

        user.setDepartment(departmentService.getById(departmentId));

        

        user.setLoginName(model.getLoginName());

        user.setName(model.getName());

        user.setGender(model.getGender());

        user.setPhoneNumber(model.getPhoneNumber());

        user.setEmail(model.getEmail());

        user.setDescription(model.getDescription());

        

        user.setRoles(new HashSet<Role>(roleService.getByIds(roleIds)));

        

        //保存到數據庫

        userService.save(user);

        return "toList";

    }

    

    /**

     * 初始化密碼爲1234

     */

    public String initPassword() throws Exception {

        //從數據庫中取出原對象

        User user = userService.getById(model.getId());

        //設置要修改的屬性

        String md5Hex = DigestUtils.md5Hex("1234");//密碼要使用md5摘要

        user.setPassword(md5Hex);

        //保存到數據庫

        userService.save(user);

        

        return "toList";

    }

    

    public Long getDepartmentId() {

        return departmentId;

    }

    public void setDepartmentId(Long departmentId) {

        this.departmentId = departmentId;

    }

    public Long[] getRoleIds() {

        return roleIds;

    }

    public void setRoleIds(Long[] roleIds) {

        this.roleIds = roleIds;

    }

}

  • Tips:這裏使用MD5加密的方法來加密,而這種方式是API的方式,因此要導入jar包:.

UserService:

public interface UserService extends DaoSupport<User>{

 

}

UserServiceImpl:

@Service

@Transactional

public class UserServiceImpl extends DaoSupportImpl<User> implements UserService{

 

    @Override

    /**

     * 初始密碼爲1234

     */

    public void save(User user) {

        String md5Hex = DigestUtils.md5Hex("1324");    //要使用md5摘要

        user.setPassword(md5Hex);

        //保存到數據庫

        getSession().save(user);

    }

}

Tips:這裏是重寫了save()方法,建立用戶的同時就將密碼初始化爲"1234".

Struts.xml:

    <!-- 用戶管理 -->

    <action name="user_*" class="userAction" method="{1}">

        <result name="list">/WEB-INF/jsp/userAction/list.jsp</result>

        <result name="saveUI">/WEB-INF/jsp/userAction/saveUI.jsp</result>

        <result name="toList" type="redirectAction">user_list</result>

    </action>

List.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>

<head>

<title>用戶列表</title>

<%@include file="/WEB-INF/jsp/public/header.jspf" %>

</head>

<body>

 

<div id="Title_bar">

<div id="Title_bar_Head">

<div id="Title_Head"></div>

<div id="Title"><!--頁面標題-->

<img border="0" width="13" height="13" src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/>用戶管理

</div>

<div id="Title_End"></div>

</div>

</div>

 

<div id="MainArea">

<table cellspacing="0" cellpadding="0" class="TableStyle">

 

<!-- 表頭-->

<thead>

<tr align=center valign=middle id=TableTitle>

<td width="100">登陸名</td>

<td width="100">姓名</td>

<td width="100">所屬部門</td>

<td width="200">崗位</td>

<td>備註</td>

<td>相關操做</td>

</tr>

</thead>

 

<!--顯示數據列表-->

<tbody id="TableData" class="dataContainer" datakey="userList">

    <s:iterator value="userList">

<tr class="TableDetail1 template">

<td>${loginName}&nbsp;</td>

<td>${name}&nbsp;</td>

<td>${department.name}&nbsp;</td>

 

<td>

<s:iterator value="roles">

    ${name}

</s:iterator>&nbsp;

</td>

 

<td>${description}&nbsp;</td>

<td><s:a action="user_delete?id=%{id}" onClick="return delConfirm()">刪除</s:a>

<s:a action="user_editUI?id=%{id}" >修改</s:a>

                    <s:a action="user_initPassword?id=%{id}" onClick="return window.confirm('您肯定要初始化密碼爲1234嗎?')">初始化密碼</s:a>

</td>

</tr>

</s:iterator>

</tbody>

</table>

 

<!-- 其餘功能超連接 -->

<div id="TableTail">

<div id="TableTail_inside">

<s:a action="user_addUI"><img src="${pageContext.request.contextPath}/style/images/createNew.png" /></s:a>

</div>

</div>

</div>

 

</body>

</html>

Tips:在遍歷userList時,roles也要被遍歷出來,這裏roles只是user對象的一個屬性.

正常狀況下EL表達式是不能搜索值棧中的數據的,但在Struts2環境中卻能夠,這是由於Struts2對其進行了加強:

因此EL表達式的查找順序:

1, 原始的順序:page, request, session, application

2, 在Struts2中:page, request, ValueStack(即值棧), session, application

 

因此在list.jsp中對userList進行的迭代,能夠用EL表達式.(如今用的也是EL表達式)

 

addUI.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>

<head>

    <title>用戶信息</title>

<%@include file="/WEB-INF/jsp/public/header.jspf" %>

</head>

<body>

 

<!-- 標題顯示 -->

<div id="Title_bar">

<div id="Title_bar_Head">

<div id="Title_Head"></div>

<div id="Title"><!--頁面標題-->

<img border="0" width="13" height="13" src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/>用戶信息

</div>

<div id="Title_End"></div>

</div>

</div>

 

<!--顯示錶單內容-->

<div id=MainArea>

<s:form action="user_%{id == null ? 'add' : 'edit'}">

    <s:hidden name="id"></s:hidden>

<div class="ItemBlock_Title1"><!-- 信息說明 --><div class="ItemBlock_Title1">

    <img border="0" width="4" height="7" src="${pageContext.request.contextPath}/style/blue/images/item_point.gif" />用戶信息 </div>

</div>

 

<!-- 表單內容顯示 -->

<div class="ItemBlockBorder">

<div class="ItemBlock">

<table cellpadding="0" cellspacing="0" class="mainForm">

<tr><td width="100">所屬部門</td>

<td>

    <s:select name="departmentId" cssClass="SelectStyle"

    list="departmentList" listKey="id" listValue="name"

    headerKey="" headerValue="==請選擇==">

</s:select>

</td>

</tr>

<tr><td>登陸名</td>

<td><s:textfield type="text" name="loginName" cssClass="InputStyle"/> *

                            (登陸名要惟一)

                        </td>

</tr>

<tr><td>姓名</td>

<td><s:textfield type="text" name="name" cssClass="InputStyle"/> *</td>

</tr>

                    <tr><td>性別</td>

<td>

    <s:radio name="gender" list="%{ {'' , ''} }"></s:radio>

                        </td>

</tr>

                    <tr><td>聯繫電話</td>

<td><s:textfield type="text" name="phoneNumber" cssClass="InputStyle"/></td>

</tr>

<tr><td>E-mail</td>

<td><s:textfield type="text" name="email" cssClass="InputStyle"/></td>

</tr>

<tr><td>備註</td>

<td><s:textarea name="description" cssClass="TextareaStyle"></s:textarea></td>

</tr>

</table>

</div>

</div>

 

        <div class="ItemBlock_Title1"><!-- 信息說明 --><div class="ItemBlock_Title1">

    <img border="0" width="4" height="7" src="${pageContext.request.contextPath}/style/blue/images/item_point.gif" />崗位設置 </div>

</div>

 

<!-- 表單內容顯示 -->

<div class="ItemBlockBorder">

<div class="ItemBlock">

<table cellpadding="0" cellspacing="0" class="mainForm">

<tr>

                        <td width="100">崗位</td>

                        <td>

                            <s:select multiple="true" cssClass="SelectStyle" size="10"

                             name="roleIds" list="roleList" listKey="id" listValue="name">

                            </s:select>按住Ctrl鍵能夠多選或取消選擇

</td>

</tr>

</table>

</div>

</div>        

          

<!-- 表單操做 -->

<div id="InputDetailBar">

<input type="image" src="${pageContext.request.contextPath}/style/images/save.png"/>

<a href="javascript:history.go(-1);"><img src="${pageContext.request.contextPath}/style/images/goBack.png"/></a>

</div>

</s:form>

</div>

 

<div class="Description">

    說明:<br />

    1,用戶的登陸名要惟一,在填寫時要同時檢測是否可用。<br />

    2,新建用戶後,密碼被初始化爲"1234"<br />

    3,密碼在數據庫中存儲的是MD5摘要(不是存儲明文密碼)。<br />

    4,用戶登陸系統後可使用"我的設置修改密碼"功能修改密碼。<br />

    5,新建用戶後,會自動指定默認的頭像。用戶可使用"我的設置我的信息"功能修改自已的頭像<br />

    6,修改用戶信息時,登陸名不可修改。

</div>

 

</body>

</html>

Tip:圖示效果其實也是由下拉選來完成的,只不過添加了multiple="true",這樣就能夠多選了.

 

在添加用戶時,如果沒有選擇任一崗位,則會報錯,由於ids爲空,故要對DaoSupportImpl進行相應修改:

DaoSupportImpl:

    /**

     * 根據id數組查詢多個

     */

    public List<T> getByIds(Long[] ids) {

        if(ids == null || ids.length == 0){

            return Collections.EMPTY_LIST;

        }

        

        // 注意空格 sql語句:from與類名之間有一空格不能省略類名與where之間有一空格不能省略

        return getSession().createQuery(//

                "from " + clazz.getSimpleName() + " where id in (:ids)")//

                .setParameterList("ids", ids)//注意:必定要使用setParameterList()方法

                .list();

    }

Tips:空格千萬不能省略.

相關文章
相關標籤/搜索