添加或者修改時,上級部門的格式如圖:.解決此功能將面臨兩個問題: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:空格千萬不能省略.