添加或者修改时,上级部门的格式如图:.解决此功能将面临两个问题:1.将全部部门名称如下拉选的形式展现出来2.以树状结构展现.在此咱们先解决问题1.javascript
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"/> </td> <td><s:property value="parent.name"/> </td> <td><s:property value="description"/> </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); } } |
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"; } } |
部门的级联删除(删除一个部门时,其子部门也会被删除)(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"/> </td> <td><s:property value="description"/> </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方法中),列表页面就会显示相应的子部门列表了.
从列表转到添加页面时,下拉选默认显示原列表的上级部门名称:
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"/> </td> <td><s:property value="description"/> </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"/> </td> <td><s:property value="description"/> </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>
<!-- 配置Spring的OpenSessionInViewFilter以解决懒加载异常的问题 --> <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的核心过滤器的前面,否则他不给放行.
使用递归遍从来展现树状结构.
遍历部门数,把全部部门名称都改掉后放到同一个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:结束这次循环,进行下一次的循环.
效果:在此,研发部>二级研发部>三级研发部,则在修改研发部的页面上,上级部门下拉选中就不会出现二级和三级研发部,在修改二级研发部的页面上,上级部门下拉选中就不会出现三级研发部.
修改代码模板(好比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; } } |
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} </td> <td>${name} </td> <td>${department.name} </td>
<td> <s:iterator value="roles"> ${name} </s:iterator> </td>
<td>${description} </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:空格千万不能省略.