-

菜單管理設計說明
-
業務設計說明
菜單管理又稱為資源管理,是系統資源對外的表現形式。本模塊主要是實現對菜單進行添加、修改、查詢、刪除等操作,其表設計語句如下:
CREATE TABLE `sys_menus` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL COMMENT '資源名稱', `url` varchar(200) DEFAULT NULL COMMENT '資源URL', `type` int(11) DEFAULT NULL COMMENT '類型 1:菜單 2:按鈕', `sort` int(11) DEFAULT NULL COMMENT '排序', `note` varchar(100) DEFAULT NULL COMMENT '備注', `parentId` int(11) DEFAULT NULL COMMENT '父菜單ID,一級菜單為0', `permission` varchar(500) DEFAULT NULL COMMENT '授權(如:sys:user:create)', `createdTime` datetime DEFAULT NULL COMMENT '創建時間', `modifiedTime` datetime DEFAULT NULL COMMENT '修改時間', `createdUser` varchar(20) DEFAULT NULL COMMENT '創建用戶', `modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用戶', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='資源管理';
菜單表與角色表是多對多的關系,在表設計時,多對多關系通常由中間表(關系表)進行維護,如圖-1所示:

基於角色菜單表的設計,其角色和菜單對應的關系數據要存儲到關系表中,其具體存
儲形式,如圖-2所示:

菜單與角色的關系表腳本設計如下:
CREATE TABLE `sys_role_menus` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_id` int(11) DEFAULT NULL COMMENT '角色ID', `menu_id` int(11) DEFAULT NULL COMMENT 'ID', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色與菜單對應關系';
-
原型設計說明
基於用戶需求,實現菜單靜態頁面(html/css/js),通過靜態頁面為用戶呈現菜單模塊的基本需求實現。
當在主頁左側菜單欄,點擊菜單管理時,在主頁內容呈現區,呈現菜單列表頁面,如
圖-3所示。

當在菜單列表頁面點擊添加按鈕時,異步加載菜單編輯頁面,並在列表內容呈現區,
呈現菜單編輯頁面,如圖-4所示。

在菜單編輯頁面選擇上級菜單時,異步加載菜單信息,並以樹結構的形式呈現上級菜
單,如圖-5所示。

-
API設計說明
菜單管理業務后台API分層架構及調用關系如圖-6所示:

-
菜單管理列表頁面呈現
-
業務時序分析
菜單管理頁面的加載過程,其時序分析如圖-7所示:

-
Controller實現
-
業務描述與設計實現
基於菜單管理的請求業務,在PageController中添加doMenuUI方法,用於返回菜單列表頁面。
-
關鍵代碼設計與實現
第一步:在PageController中定義返回菜單列表的方法。代碼如下:
@RequestMapping("menu/menu_list")
public String doMenuUI() {
return "sys/menu_list";
}
第二步:在PageController中基於rest風格的url方式優化返回UI頁面的方法。找出共性進行提取,例如:
@RequestMapping("{module}/{moduleUI}")
public String doModuleUI(@PathVariable String moduleUI) {
return "sys/"+moduleUI;
}
-
客戶端實現
-
首頁菜單事件處理
-
業務描述與設計實現
首先准備菜單列表頁面(/templates/pages/sys/menu_list.html),然后在starter.html頁面中點擊菜單管理時異步加載菜單列表頁面。
-
關鍵代碼設計與實現
找到項目中的starter.html頁面,頁面加載完成以后,注冊菜單管理項的點擊事件,當點擊菜單管理時,執行事件處理函數。關鍵代碼如下:
$(function(){ … doLoadUI("load-menu-id","menu/menu_list") })
說明:對於doLoadUI函數,假如在starter.html中已經定義,則無需再次定義.
function doLoadUI(id,url){ $("#"+id).click(function(){ $("#mainContentId").load(url); }); }
菜單管理列表數據呈現
-
數據架構分析
菜單列表頁面加載完成,啟動菜單數據異步加載操作,本次菜單列表頁面要呈現菜單以及2息,其數據查詢時,數據的封裝及傳遞過程,如圖-8所示。

說明:本模塊將從數據庫查詢到的菜單數據封裝到map對象,一行記錄一個map對象,其中key為表中的字段(列)名,值為字段(列)對應的值。時序圖如下

-
服務端關鍵業務及代碼實現
-
Dao接口實現
-
業務描述及設計實現
通過數據層對象,基於業務層參數,查詢菜單以及上級菜單信息(要查詢上級菜單名)。
-
關鍵代碼分析及實現
第一步:定義數據層接口對象,通過此對象實現數據庫中菜單數據的訪問操作。關鍵代碼如下:
@Mapper public interface SysMenuDao { }
第二步:在SysMenuDao接口中添加findObjects方法,基於此方法實現菜單數據的查詢操作。代碼如下:
List<Map<String,Object>> findObjects();
-
Mapper文件實現
-
業務描述及設計實現
基於Dao接口創建映射文件,在此文件中通過相關元素(例如select)描述要執行的數據操作。
-
關鍵代碼設計及實現
第一步:在映射文件的設計目錄中添加SysMenuMapper.xml映射文件,代碼如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.cy.pj.sys.dao.SysMenuDao"> </mapper>
第二步:在映射文件中添加id為findObjects的元素,實現菜單記錄查詢。我們要查詢所有菜單以及菜單對應的上級菜單名稱。關鍵代碼如下:
<select id="findObjects" resultType="map"> <!-- 方案1 select c.*,p.name parentName from sys_menus c left join sys_menus p on c.parentId=p.id --> <!-- 方案2 --> select c.*,( select p.name from sys_menus p where c.parentId=p.id ) parentName from sys_menus c </select>
說明:自關聯查詢分析,如圖-10所示:

-
Service接口及實現類
-
業務描述與設計實現
在菜單查詢中,業務層對象主要是借助數據層對象完成菜單數據的查詢。后續還可以基於AOP對數據進行緩存,記錄訪問日志等。
-
關鍵代碼設計及實現
第一步:定義菜單業務接口及方法,暴露外界對菜單業務數據的訪問,其代碼參考如下:
package com.cy.pj.sys.service; public interface SysMenuService { List<Map<String,Object>> findObjects(); }
第二步:定義菜單業務接口實現類,並添加菜單業務數據對應的查詢操作實現,其代碼參考如下:
package com.cy.pj.sys.service.impl; @Service public class SysMenuServiceImpl implements SysMenuService{ @Autowired private SysMenuDao sysMenuDao; @Override public List<Map<String, Object>> findObjects() { List<Map<String,Object>> list= sysMenuDao.findObjects(); if(list==null||list.size()==0) throw new ServiceException("沒有對應的菜單信息"); return list; }
-
Controller類實現
-
業務描述與設計實現
控制層對象主要負責請求和響應數據的處理,例如,本模塊通過業務層對象執行業務邏輯,再通過VO對象封裝響應結果(主要對業務層數據添加狀態信息),最后將響應結果轉換為JSON格式的字符串響應到客戶端。
-
關鍵代碼設計與實現
定義Controller類,並將此類對象使用Spring框架中的@Controller注解進行標識,表示此類對象要交給Spring管理。然后基於@RequestMapping注解為此類定義根路徑映射。代碼參考如下:
package com.cy.pj.sys.controller; @RequestMapping("/menu/") @RestController public class SysMenuController { }
說明:這里的@RestController注解等效於在類上同時添加了@Controller和 @ResponseBody注解.
在Controller類中添加菜單查詢處理方法,代碼參考如下:
@RequestMapping("doFindObjects")
public JsonResult doFindObjects() {
return new JsonResult(sysMenuService.findObjects());
}
-
客戶端關鍵業務及代碼實現
-
菜單列表信息呈現
-
業務描述與設計實現
菜單頁面加載完成以后,向服務端發起異步請求加載菜單信息,當菜單信息加載完成需要將菜單信息呈現到列表頁面上。
-
關鍵代碼設計與實現
第一步:在菜單列表頁面引入treeGrid插件相關的JS。
<script type="text/javascript" src="bower_components/treegrid/jquery.treegrid.extension.js"></script> <script type="text/javascript" src="bower_components/treegrid/jquery.treegrid.min.js"></script> <script type="text/javascript" src="bower_components/treegrid/tree.table.js"></script>
第二步:在菜單列表頁面,定義菜單列表配置信息,關鍵代碼如下:
var columns = [ { field : 'selectItem', radio : true }, { title : '菜單ID', field : 'id', align : 'center', valign : 'middle', width : '80px' }, { title : '菜單名稱', field : 'name', align : 'center', valign : 'middle', width : '130px' }, { title : '上級菜單', field : 'parentName', align : 'center', valign : 'middle', sortable : true, width : '100px' }, { title : '類型', field : 'type', align : 'center', valign : 'middle', width : '70px', formatter : function(item, index) { if (item.type == 1) { return '<span class="label label-success">菜單</span>'; } if (item.type == 2) { return '<span class="label label-warning">按鈕</span>'; } } }, { title : '排序號', field : 'sort', align : 'center', valign : 'middle', sortable : true, width : '70px' }, { title : '菜單URL', field : 'url', align : 'center', valign : 'middle', width : '160px' }, { title : '授權標識',//要顯示的標題名稱 field : 'permission',//json串中的key align : 'center',//水平居中 valign : 'middle',//垂直居中 sortable : false //是否排序 } ];//格式來自官方demos -->treeGrid(jquery擴展的一個網格樹插件)
第三步:定義異步請求處理函數,代碼參考如下:
function doGetObjects(){//treeGrid //1.構建table對象(bootstrap框架中treeGrid插件提供) var treeTable=new TreeTable( "menuTable",//tableId "menu/doFindObjects",//url columns); //設置從哪一列開始展開(默認是第一列) //treeTable.setExpandColumn(2); //2.初始化table對象(底層發送ajax請求獲取數據) treeTable.init();//getJSON,get(),... }
第四步:頁面加載完成,調用菜單查詢對應的異步請求處理函數,關鍵代碼如下:
$(function(){ doGetObjects(); })
-
菜單管理刪除操作實現
-
業務時序分析
基於用戶在列表頁面上選擇的的菜單記錄ID,執行刪除操作,本次刪除業務實現中,首先要基於id判斷當前菜單是否有子菜單,假如有子菜單則不允許刪除,沒有則先刪除菜單角色關系數據,然后再刪除菜單自身信息。其時序分析如圖-11所示:

-
服務端關鍵業務及代碼實現
-
Dao接口實現
-
業務描述及設計實現
數據層基於業務層提交的菜單記錄id,刪除菜單角色關系以及菜單數據,菜單自身記錄信息。
-
關鍵代碼設計及實現
第一步:創建SysRoleMenuDao並定義基於菜單id刪除關系數據的方法,關鍵代碼如下:
@Mapper public interface SysRoleMenuDao { int deleteObjectsByMenuId(Integer menuId); }
第二步:在SysMenuDao中添加基於菜單id查詢子菜單記錄的方法。代碼參考如下:
int getChildCount(Integer id);第三步:在SysMenuDao中添加基於菜單id刪除菜單記錄的方法。代碼參考如下:
int deleteObject(Integer id);-
Mapper文件實現
-
業務描述及設計實現
在SysRoleMenuDao,SysMenuDao接口對應的映射文件中添加用於執行刪除業務的delete元素,然后在元素內部定義具體的SQL實現。
-
關鍵代碼設計與實現
第一步:創建SysRoleMenuMapper.xml文件並添加基於菜單id刪除關系數據的元素,關鍵代碼如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.cy.pj.sys.dao.SysRoleMenuDao"> <delete id="deleteObjectsByMenuId" parameterType="int"> delete from sys_role_menus where menu_id=#{menuId} </delete> </mapper>
第二步:在SysMenuMapper.xml文件中添加基於id統計子菜單數量的元素,關鍵代碼如下:
<select id="getChildCount" parameterType="int" resultType="int"> select count(*) from sys_menus where parentId=#{id} </select>
第三步:在SysMenuMapper.xml文件添加delete元素,基於帶單id刪除菜單自身記錄信息,關鍵代碼如下:
<delete id="deleteObject"> delete from sys_menus where id =#{id} </delete
-
Service接口及實現類
-
業務描述與設計實現
在菜單業務層定義用於執行菜單刪除業務的方法,首先通過方法參數接收控制層傳遞的菜單id,並對參數id進行校驗。然后基於菜單id統計子菜單個數,假如有子菜單則拋出異常,提示不允許刪除。假如沒有子菜單,則先刪除角色菜單關系數據。最后刪除菜單自身記錄信息后並返回業務執行結果。
-
關鍵代碼設計與實現
第一步:在SysMenuService接口中,添加基於id進行菜單刪除的方法。關鍵代碼如下:
int deleteObject(Integer id);第二步:在SysMenuServiceImpl實現類中注入SysRoleMenuDao相關對象。關鍵代碼如下:
@Autowired private SysRoleMenuDao sysRoleMenuDao;
第三步:在SysMenuServiceImpl實現類中添加刪除業務的具體實現。關鍵代碼如下
@Override public int deleteObject(Integer id) { //1.驗證數據的合法性 if(id==null||id<=0) throw new IllegalArgumentException("請先選擇"); //2.基於id進行子元素查詢 int count=sysMenuDao.getChildCount(id); if(count>0) throw new ServiceException("請先刪除子菜單"); //3.刪除角色,菜單關系數據 sysRoleMenuDao.deleteObjectsByMenuId(id); //4.刪除菜單元素 int rows=sysMenuDao.deleteObject(id); if(rows==0) throw new ServiceException("此菜單可能已經不存在"); //5.返回結果 return rows; }
-
Controller類實現
-
業務描述與設計實現
在菜單控制層對象中,添加用於處理菜單刪除請求的方法。首先在此方法中通過形參接收客戶端提交的數據,然后調用業務層對象執行刪除操作,最后封裝執行結果,並在運行時將響應對象轉換為JSON格式的字符串,響應到客戶端。
-
關鍵代碼設計與實現
第一步:在SysMenuController中添加用於執行刪除業務的方法。代碼如下:
@RequestMapping("doDeleteObject") public JsonResult doDeleteObject(Integer id){ sysMenuService.deleteObject(id); return new JsonResult("delete ok"); }第二步:啟動tomcat進行訪問測試,打開瀏覽器輸入如下網址:http://localhost/menu/doDeleteObject?id=10
-
客戶端關鍵業務及代碼實現
-
菜單列表頁面事件處理
-
業務描述及設計實現
用戶在頁面上首先選擇要刪除的元素,然后點擊刪除按鈕,將用戶選擇的記錄id異步提交到服務端,最后在服務端執行菜單的刪除動作。
-
關鍵代碼設計與實現
第一步:頁面加載完成以后,在刪除按鈕上進行點擊事件注冊。關鍵代碼如下:
$(".input-group-btn") .on("click",".btn-delete",doDeleteObject)第二步:定義刪除操作對應的事件處理函數。關鍵代碼如下:
function doDeleteObject(){ //1.獲取選中的記錄id var id=doGetCheckedId(); if(!id){ alert("請先選擇"); return; } //2.給出提示是否確認刪除 if(!confirm("確認刪除嗎"))return; //3.異步提交請求刪除數據 var url="menu/doDeleteObject"; var params={"id":id}; $.post(url,params,function(result){ if(result.state==1){ alert(result.message); $("tbody input[type='radio']:checked") .parents("tr").remove(); }else{ alert(result.message); } }); }
第三步:定義獲取用戶選中的記錄id的函數。關鍵代碼如下:
function doGetCheckedId(){ //1.獲取選中的記錄 var selections=$("#menuTable") //bootstrapTreeTable是treeGrid插件內部定義的jquery擴展函數 //getSelections為擴展函數內部要調用的一個方法 .bootstrapTreeTable("getSelections"); //2.對記錄進行判定 if(selections.length==1) return selections[0].id; }
-
菜單添加頁面呈現
-
業務時序分析
添加頁面加載時序分析,如圖-12所示:

-
准備菜單編輯頁面
首先准備菜單列表頁面(/templates/pages/sys/menu_edit.html),然后在menu_list.html頁面中點擊菜單添加時異步加載菜單編輯頁面。
-
菜單編輯頁面呈現
-
業務描述與設計實現
菜單列表頁面點擊添加按鈕時,異步加載菜單編輯頁面。
-
關鍵代碼設計與實現
第一步:菜單列表頁面上,對添加按鈕進行事件注冊,關鍵代碼如下:
在menu_edit.html頁面中定義用於呈現樹結構的DIV組件
<div class="layui-layer layui-layer-page layui-layer-molv layer-anim" id="menuLayer" type="page" times="2" showtime="0" contype="object" style="z-index:59891016; width: 300px; height: 450px; top: 100px; left: 500px; display:none"> <div class="layui-layer-title" style="cursor: move;">選擇菜單</div> <div class="layui-layer-content" style="height: 358px;"> <div style="padding: 10px;" class="layui-layer-wrap"> <ul id="menuTree" class="ztree"></ul> <!-- 動態加載樹 --> </div> </div> <span class="layui-layer-setwin"> <a class="layui-layer-ico layui-layer-close layui-layer-close1 btn-cancel" ></a></span> <div class="layui-layer-btn layui-layer-btn-"> <a class="layui-layer-btn0 btn-confirm">確定</a> <a class="layui-layer-btn1 btn-cancel">取消</a> </div> </div>
-
ZTree數據呈現
-
業務描述與設計實現
引入zTree需要的JS,並,並基於JS中的定義的API初始化zTree中的菜單信息。
-
關鍵代碼設計與實現
第一步:引入js文件
<script type="text/javascript" src="bower_components/ztree/jquery.ztree.all.min.js"></script> <script type="text/javascript" src="bower_components/layer/layer.js"> </script>
第二步:在menu_edit.html中定義zTree配置信息(初始化zTree時使用)
var zTree; var setting = { data : { simpleData : { enable : true, idKey : "id", //節點數據中保存唯一標識的屬性名稱 pIdKey : "parentId", //節點數據中保存其父節點唯一標識的屬性名稱 rootPId : null //根節點id } } }
第二步:定義異步加載zTree信息的函數,關鍵代碼如下:
function doLoadZtreeNodes(){ var url="menu/doFindZtreeMenuNodes"; //異步加載數據,並初始化數據 $.getJSON(url,function(result){ if(result.state==1){ //使用init函數需要先引入ztree對應的js文件 zTree=$.fn.zTree.init( $("#menuTree"), setting, result.data); $("#menuLayer").css("display","block"); }else{ alert(result.message); } }) }
第三步:定義zTree中取消按鈕事件處理函數,點擊取消隱藏zTree。關鍵代碼如下:
function doHideTree(){ $("#menuLayer").css("display","none"); }
第四步:定義zTree中確定按鈕對應的事件處理處理函數。關鍵代碼如下:
function doSetSelectNode(){ //1.獲取選中的節點對象 var nodes=zTree.getSelectedNodes(); if(nodes.length==1){ var node=nodes[0]; console.log(node); //2.將對象中內容,填充到表單 $("#parentId").data("parentId",node.id); $("#parentId").val(node.name); } //3.隱藏樹對象 doHideTree(); }
第五步:定義頁面加載完成以后的事件處理函數:
$(document).ready(function(){ $("#mainContentId") .on("click",".load-sys-menu",doLoadZtreeNodes) $("#menuLayer") .on("click",".btn-confirm",doSetSelectNode) .on("click",".btn-cancel",doHideTree) });
-
菜單數據添加實現
-
數據基本架構分析
用戶在菜單編輯頁面輸入數據,然后異步提交到服務端,其簡易數據傳遞基本架構,如圖-14所示:

用戶在菜單添加頁面中填寫好菜單數據,然后點擊保存按鈕,將用戶填寫的數據添加
到數據庫。其時序分析,如圖-15所示:

-
服務端關鍵業務及代碼實現
-
Entity類定義
-
業務描述與設計實現
定義持久化對象,封裝客戶端請求數據,並將數據傳遞到數據層進行持久化。
-
關鍵代碼設計與實現
菜單持久層對象類型定義,關鍵代碼如下:
import lombok.Data;
@Data public class SysMenu implements Serializable{ private static final long serialVersionUID = -8805983256624854549L; private Integer id; /**菜單名稱*/ private String name; /**菜單url: log/doFindPageObjects*/ private String url; /**菜單類型(兩種:按鈕,普通菜單)*/ private Integer type=1; /**排序(序號)*/ private Integer sort; /**備注*/ private String note; /**上級菜單id*/ private Integer parentId; /**菜單對應的權限標識(sys:log:delete)*/ private String permission; /**創建用戶*/ private String createdUser; /**修改用戶*/ private String modifiedUser; private Date createdTime; private Date modifiedTime;-
DAO接口定義
-
業務描述與設計實現
負責將用戶提交的菜單數據,持久化到數據庫。
-
關鍵代碼設計與實現
在SysMenuDao接口中定義數據持久化方法:
int insertObject(SysMenu entity);-
Mapper映射文件定義
-
業務描述與設計實現
基於SysMenuDao中方法的定義,編寫用於實現菜單添加的SQL元素。
-
關鍵代碼設計與實現
在SysMenuMapper.xml中添加insertObject元素,用於寫入菜單信息。關鍵代碼如下:
<insert id="insertObject" parameterType="com.cy.pj.sys.entity.SysMenu"> insert into sys_menus (name,url,type,sort,note,parentId,permission, createdTime,modifiedTime,createdUser,modifiedUser) values (#{name},#{url},#{type},#{sort},#{note},#{parentId}, #{permission},now(),now(),#{createdUser},#{modifiedUser}) </insert>
-
Service接口定義及實現
-
業務描述與設計實現
基於控制層請求,調用數據層對象將菜單信息寫入到數據庫中。
-
關鍵代碼設計與實現
第一步:在SysMenuService接口中,添加用於保存菜單對象的方法。關鍵代碼如下
int saveObject(SysMenu entity);
第二步:在SysMenuServiceImpl類中,實現菜單保存操作。關鍵代碼如下:
@Override public int saveObject(SysMenu entity) { //1.合法驗證 if(entity==null) throw new IllegalArgumentException("保存對象不能為空"); if(StringUtils.isEmpty(entity.getName())) throw new IllegalArgumentException("菜單名不能為空"); //2.保存數據 int rows=sysMenuDao.insertObject(entity); //3.返回數據 return rows; }-
Controller類定義
-
業務描述與設計實現
接收客戶端提交的菜單數據,並對其進行封裝,然后調用業務層對象進行業務處理,最后將業務層處理結果響應到客戶端。
-
關鍵代碼設計與實現
定義Controller方法,借助此方法處理保存菜單數據請求和響應邏輯。關鍵代碼如下:
@RequestMapping("doSaveObject") public JsonResult doSaveObject(SysMenu entity){ sysMenuService.saveObject(entity); return new JsonRehlt("save ok"); }-
客戶端關鍵業務及代碼實現
-
頁面cancel按鈕事件處理
-
業務描述與設計實現
點擊頁面cancel按鈕時,加載菜單那列表頁面。
-
關鍵代碼設計與實現
第一步:事件注冊(頁面加載完成以后)
$(".box-footer") .on("click",".btn-cancel",doCancel)第二步:事件處理函數定義
function doCancel(){ var url="menu/menu_list"; $("#mainContentId").load(url); }
-
頁面Save按鈕事件處理
-
業務描述與設計實現
點擊頁面save按鈕時,將頁面上輸入的菜單信息異步提交到服務端。
-
關鍵代碼設計與實現
第一步:事件注冊(頁面加載完成以后)
$(".box-footer") .on("click",".btn-save",doSaveOrUpdate)第二步:Save按鈕事件處理函數定義。關鍵代碼如下:
function doSaveOrUpdate(){ //1.獲取表單數據 var params=doGetEditFormData(); //2.定義url var url="menu/doSaveObject"; //3.異步提交數據 $.post(url,params,function(result){ if(result.state==1){ alert(result.message); doCancel(); }else{ alert(result.message); } }); }
第三步:表單數據獲取及封裝函數定義。關鍵代碼如下:
function doGetEditFormData(){ var params={ type:$("form input[name='typeId']:checked").val(), name:$("#nameId").val(), url:$("#urlId").val(), sort:$("#sortId").val(), permission:$("#permissionId").val(), parentId:$("#parentId").data("parentId") } return params; }
-
菜單修改頁面數據呈現
-
業務時序分析
當在菜單列表頁面中選中某條記錄,然后點擊修改按鈕時,其業務時序分析如圖-16所示:

-
客戶端關鍵業務及代碼實現
-
列表頁面修改按鈕事件處理
-
業務描述與設計實現
點擊頁面修改按鈕時,獲取選中菜單記錄,並異步加載編輯頁面。
-
關鍵代碼設計與實現
第一步:列表頁面修改按鈕事件注冊,關鍵代碼如下:
$(".input-group-btn") .on("click",".btn-update",doLoadEditUI);第二步:修改按鈕事件處理函數定義或修改,關鍵代碼如下:
function doLoadEditUI(){ var title; if($(this).hasClass("btn-add")){ title="添加菜單" }else if($(this).hasClass("btn-update")){ title="修改菜單" //獲取選中的記錄數據 var rowData=doGetCheckedItem(); if(!rowData){ alert("請選擇一個"); return; } $("#mainContentId").data("rowData",rowData); } var url="menu/menu_edit"; $("#mainContentId").load(url,function(){ $(".box-title").html(title); }) }
第三步:獲取用戶選中記錄的函數定義。關鍵代碼如下:
function doGetCheckedItem(){ var tr=$("tbody input[type='radio']:checked") .parents("tr"); return tr.data("rowData"); }
-
編輯頁面菜單數據呈現
-
業務描述與設計實現
頁面加載完成,在頁面指定位置呈現要修改的數據。
-
關鍵代碼設計與實現
第一步:頁面加載完成以后,獲取頁面div中綁定的數據。關鍵代碼如下:
$(function(){ … //假如是修改 var data=$("#mainContentId").data("rowData"); if(data)doInitEditFormData(data); });
第二步:定義編輯頁面數據初始化方法。關鍵代碼如下:
function doInitEditFormData(data){ /* $("input[type='radio']").each(function(){ if($(this).val()==data.type){ $(this).prop("checked",true); } }) */ $(".typeRadio input[value='"+data.type+"']").prop("checked",true); $("#nameId").val(data.name); $("#sortId").val(data.sort); $("#urlId").val(data.url); $("#permissionId").val(data.permission); $("#parentId").val(data.parentName); $("#parentId").data("parentId",data.parentId); }
-
菜單數據更新實現
-
業務時序分析
當點擊編輯頁面更新按鈕時,其時序分析如圖-17所示:

-
服務端關鍵業務及代碼實現
-
DAO接口實現
-
業務描述與設計實現
負責將用戶編輯頁面提交到服務端的菜單數據,更新到數據庫進行持久性存儲。
-
關鍵代碼設計與實現
在SysMenuDao接口中添加數據更新方法,關鍵代碼如下:
int updateObject(SysMenu entity);-
Mapper映射文件定義
-
業務描述與設計實現
基於SysMenuDao中updateObject方法的定義,編寫用於實現菜單更新的SQL元素。
-
關鍵代碼設計與實現
在SysMenuMapper.xml中添加updateObject元素,用於更新菜單信息。關鍵代碼如下:
<update id="updateObject" parameterType="com.cy.pj.sys.entity.SysMenu"> update sys_menus set name=#{name}, type=#{type}, sort=#{sort}, url=#{url}, parentId=#{parentId}, permission=#{permission}, modifiedUser=#{modifiedUser}, modifiedTime=now() where id=#{id} </update>
-
Service接口及實現
-
業務描述與設計實現
基於控制層請求,對數據進行校驗並調用數據層對象將菜單信息更新到數據庫中。
-
關鍵代碼設計與實現
第一步:在SysMenuService接口中,添加用於更新菜單對象的方法。關鍵代碼如下
int updateObject(SysMenu entity);第二步:在SysMenuServiceImpl類中,實現菜單保存操作。關鍵代碼如下:
@Override public int updateObject(SysMenu entity) { //1.合法驗證 if(entity==null) throw new ServiceException("保存對象不能為空"); if(StringUtils.isEmpty(entity.getName())) throw new ServiceException("菜單名不能為空"); //2.更新數據 int rows=sysMenuDao.updateObject(entity); if(rows==0) throw new ServiceException("記錄可能已經不存在"); //3.返回數據 return rows; }
-
Controller類定義
-
業務描述與設計實現
接收客戶端提交的菜單數據,並對其進行封裝,然后調用業務層對象進行業務處理,最后將業務層處理結果響應到客戶端。
-
關鍵代碼設計與實現
定義Controller方法,借助此方法處理保存菜單數據請求和響應邏輯。關鍵代碼如下
@RequestMapping("doUpdateObject") public JsonResult doUpdateObject( SysMenu entity){ sysMenuService.updateObject(entity); return new JsonResult("update ok"); }-
客戶端關鍵業務及代碼實現
-
編輯頁面更新按鈕事件處理
-
業務描述與設計實現
點擊頁面save按鈕時,將頁面上輸入的菜單編輯信息提交到服務端。
-
關鍵代碼設計與實現
編輯Save按鈕對應的事件處理函數。關鍵代碼如下:
function doSaveOrUpdate(){ //1.獲取表單數據 var params=doGetEditFormData(); var rowData=$("#mainContentId").data("rowData"); //2.定義url var insertUrl="menu/doSaveObject"; var updateUrl="menu/doUpdateObject"; var url=rowData?updateUrl:insertUrl; if(rowData)params.id=rowData.id; //3.異步提交數據 $.post(url,params,function(result){ if(result.state==1){ alert(result.message); doCancel(); }else{ alert(result.message); } }); }
-
重難點分析
-
菜單管理在整個系統中的定位(資源管理)。
-
菜單數據的自關聯查詢實現(查詢當前菜單以及這個菜單的上級菜單)。
-
菜單管理中數據的封裝過程(請求數據,響應數據)。
-
菜單數據在客戶端的呈現。(treeGrid,zTree)
-
FAQ分析
-
菜單表是如何設計的,都有哪些字段?
-
菜單列表數據在客戶端是如何展示的?(TreeGrid)
-
菜單刪除業務是如何處理的?
-
菜單編輯頁面中上級菜單數據的呈現方式?(zTree)
-
常用表連接方式,如圖-18所示:
-

-
-
-
