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:空格千万不能省略.

相关文章
相关标签/搜索