1. 业务设计说明

    菜单治理又称为资源管理,是系统资源对外的表现形式。本模块次要是实现对菜单进行增加、批改、查问、删除等操作。其表设计语句如下:

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='角色与菜单对应关系';
  1. 原型设计说明

    基于用户需要,实现菜单动态页面(html/css/js),通过动态页面为用户出现菜单模块的根本需要实现。当在主页左侧菜单栏,点击菜单治理时,在主页内容出现区,出现菜单列表页面,如图-3所示。

当在菜单列表页面点击增加按钮时,异步加载菜单编辑页面,并在列表内容出现区,出现菜单编辑页面,如图-4所示。

在菜单编辑页面抉择上级菜单时,异步加载菜单信息,并以树结构的模式出现上级菜单,如图-5所示。

阐明:如果客户对此原型进行了确认,后续则能够基于此原型进行研发。

  1. API设计说明

    菜单治理业务后盾API分层架构及调用关系如图-6所示:

阐明:分层目标次要将简单问题简单化,实现各司其职,各尽所能。

  1. 菜单治理列表页面出现

  2. 业务时序剖析

    菜单治理页面的加载过程,其时序剖析如图-7所示:

  3. 服务端实现

  4. 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;}
  1. 客户端实现

  2. 首页菜单事件处理

  • 业务形容与设计实现
    首先筹备菜单列表页面(/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); });}

其中,load函数为jquery中的ajax异步申请函数。

  1. 菜单列表页面

  • 业务形容与设计实现
    本页面出现菜单信息时要以树结构模式进行出现。此树结构会借助jquery中的treeGrid插件进行实现,所以在菜单列表页面须要引入treeGrid相干JS。然而,具体的treeGrid怎么用可自行在网上进行查问(已比拟成熟)。
  • 要害代码设计与实现:

要害JS引入(menu_list.html),代码如下:

<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>
  1. 菜单治理列表数据出现

  2. 数据架构剖析

    菜单列表页面加载实现,启动菜单数据异步加载操作,本次菜单列表页面要出现菜单以及信息,其数据查问时,数据的封装及传递过程,如图-8所示。

    阐明:本模块将从数据库查问到的菜单数据封装到map对象,一行记录一个map对象,其中key为表中的字段(列)名,值为字段(列)对应的值。数据加载过程其时序剖析,如图-9所示:

  3. 服务端要害业务及代码实现

  4. Dao接口实现

  • 业务形容及设计实现

通过数据层对象,基于业务层参数,查问菜单以及上级菜单信息(要查问上级菜单名)。

  • 要害代码剖析及实现

第一步:定义数据层接口对象,通过此对象实现数据库中菜单数据的拜访操作。要害代码如下:

@Mapperpublic interface SysMenuDao {}

第二步:在SysMenuDao接口中增加findObjects办法,基于此办法实现菜单数据的查问操作。代码如下:

List<Map<String,Object>> findObjects();

阐明:一行记录映射为一个map对象,多行存储到list。

  1. 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所示:

  1. Service接口及实现类

  • 业务形容与设计实现
    在菜单查问中,业务层对象次要是借助数据层对象实现菜单数据的查问。后续还能够基于AOP对数据进行缓存,记录拜访日志等。
  • 要害代码设计及实现

第一步:定义菜单业务接口及办法,裸露外界对菜单业务数据的拜访,其代码参考如下:

package com.cy.pj.sys.service;public interface SysMenuService { List<Map<String,Object>> findObjects();}

第二步:定义菜单业务接口实现类,并增加菜单业务数据对应的查问操作实现,其代码参考如下:

package com.cy.pj.sys.service.impl;@Servicepublic 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;}
  1. Controller类实现

  • 业务形容与设计实现
    管制层对象次要负责申请和响应数据的解决,例如,本模块通过业务层对象执行业务逻辑,再通过VO对象封装响应后果(次要对业务层数据增加状态信息),最初将响应后果转换为JSON格局的字符串响应到客户端。
  • 要害代码设计与实现

定义Controller类,并将此类对象应用Spring框架中的@Controller注解进行标识,示意此类对象要交给Spring治理。而后基于@RequestMapping注解为此类定义根门路映射。代码参考如下:

package com.cy.pj.sys.controller;@RequestMapping("/menu/")@RestControllerpublic class SysMenuController {}

阐明:这里的@RestController注解等效于在类上同时增加了@Controller和  @ResponseBody注解.
在Controller类中增加菜单查询处理办法,代码参考如下:

@RequestMapping("doFindObjects")public JsonResult doFindObjects() { return new JsonResult(sysMenuService.findObjects());}
  1. 客户端要害业务及代码实现

  2. 菜单列表信息出现

  • 业务形容与设计实现
    菜单页面加载实现当前,向服务端发动异步申请加载菜单信息,当菜单信息加载实现须要将菜单信息出现到列表页面上。
  • 要害代码设计与实现

第一步:在菜单列表页面引入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();})
  1. 菜单治理删除操作实现

  2. 业务时序剖析

    -----    

    基于用户在列表页面上抉择的的菜单记录ID,执行删除操作,本次删除业务实现中,首先要基于id判断以后菜单是否有子菜单,如果有子菜单则不容许删除,没有则先删除菜单角色关系数据,而后再删除菜单本身信息。其时序剖析如图-11所示:

    1. 服务端要害业务及代码实现

  3. Dao接口实现

  • 业务形容及设计实现

数据层基于业务层提交的菜单记录id,删除菜单角色关系以及菜单数据,菜单本身记录信息。

  • 要害代码设计及实现

第一步:创立SysRoleMenuDao并定义基于菜单id删除关系数据的办法,要害代码如下:

@Mapperpublic interface SysRoleMenuDao { int deleteObjectsByMenuId(Integer menuId);}

第二步:在SysMenuDao中增加基于菜单id查问子菜单记录的办法。代码参考如下:

int getChildCount(Integer id);

第三步:在SysMenuDao中增加基于菜单id删除菜单记录的办法。代码参考如下:

int deleteObject(Integer id);
  1. 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>
  1. Service接口及实现类

  • 业务形容与设计实现
    在菜单业务层定义用于执行菜单删除业务的办法,首先通过办法参数接管管制层传递的菜单id,并对参数id进行校验。而后基于菜单id统计子菜单个数,如果有子菜单则抛出异样,提醒不容许删除。如果没有子菜单,则先删除角色菜单关系数据。最初删除菜单本身记录信息后并返回业务执行后果。
  • 要害代码设计与实现

第一步:在SysMenuService接口中,增加基于id进行菜单删除的办法。要害代码如下:

int deleteObject(Integer id);

第二步:在SysMenuServiceImpl实现类中注入SysRoleMenuDao相干对象。要害代码如下:

@Autowiredprivate 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; }
  1. 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
  1. 客户端要害业务及代码实现

  2. 菜单列表页面事件处理

  • 业务形容及设计实现

用户在页面上首先抉择要删除的元素,而后点击删除按钮,将用户抉择的记录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;}
  1. 菜单增加页面出现

  2. 业务时序剖析

增加页面加载时序剖析,如图-12所示:

  1. 筹备菜单编辑页面

    首先筹备菜单列表页面(/templates/module/sys/menu_edit.html),而后在menu_list.html页面中点击菜单增加时异步加载菜单编辑页面。

  2. 菜单编辑页面出现

  • 业务形容与设计实现

菜单列表页面点击增加按钮时,异步加载菜单编辑页面。

  • 要害代码设计与实现

第一步:菜单列表页面上,对增加按钮进行事件注册,要害代码如下:

$(document).ready(function(){ ...  $(".input-group-btn") .on("click",".btn-add",doLoadEditUI);});

第二步:定义增加按钮事件处理函数,要害代码如下:

function doLoadEditUI(){ var title; if($(this).hasClass("btn-add")){ title="增加菜单" } var url="menu/menu_edit"; $("#mainContentId").load(url,function(){ $(".box-title").html(title); })}
  1. 菜单编辑页面上级菜单出现

  2. 业务时序剖析

在菜单编辑页面上,点击上级菜单时,其数据加载时序剖析,如图-13所示:

  1. 服务端要害业务及代码实现

  2. Pojo对象

  • 业务形容与设计实现

定义值对象封装查问到的上级菜单id,name,parentId信息。

  • 要害代码设计与实现
package com.cy.pj.common.pojo;@Datepublic class Node implements Serializable{ private static final long serialVersionUID = -6577397050669133046L; private Integer id; private String name; private Integer parentId;
  1. Dao接口实现

  • 业务形容与设计实现
    基于申请获取数据库对应的菜单表中的所有菜单id,name,parentId,一行记录封装为一个Node对象,多个node对象存储到List汇合
  • 要害代码设计与实现

在SysMenuDao接口中增加,用于查问上级菜单相干信息。要害代码如下:

List<Node> findZtreeMenuNodes();
  1. Mapper映射文件

  • 业务形容与设计实现

基于SysMenuMapper中办法的定义,编写用于菜单查问的SQL元素。

  • 要害代码设计与实现

在SysMenuMapper.xml中增加findZtreeMenuNodes元素,用于查问上级菜单信息。要害代码如下:

<select id="findZtreeMenuNodes" resultType="com.cy.pj.common.vo.Node"> select id,name,parentId from sys_menus  </select>
  1. Service接口及实现类

  • 业务形容与设计实现

基于用户申请,通过数据层对象获取上级菜单相干信息。

  • 要害代码实现

第一步:在SysMenuService接口中,增加查问菜单信息的办法。要害代码如下:

List<Node> findZtreeMenuNodes()

第二步:在SysMenuServiceImpl类中增加,查问菜单信息办法的实现。要害代码如下:

@Override public List<Node> findZtreeMenuNodes() { return sysMenuDao.findZtreeMenuNodes(); }
  1. Controller类实现

  • 业务形容与设计实现

基于客户端申请,拜访业务层对象办法,获取菜单节点对象,并封装返回。

  • 要害代码设计与实现
@RequestMapping("doFindZtreeMenuNodes")public JsonResult doFindZtreeMenuNodes(){ return new JsonResult(sysMenuService.findZtreeMenuNodes());}
  1. 客户端要害业务及代码实现

  2. ZTree构造定义

  • 业务形容与设计实现

本模块以开源JS组件形式实现ZTree构造信息的出现。

  • 要害代码设计与实现

在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>
  1. 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) });
  1. 菜单数据增加实现

  2. 数据根本架构剖析

用户在菜单编辑页面输出数据,而后异步提交到服务端,其繁难数据传递根本架构,如图-14所示:

用户在菜单增加页面中填写好菜单数据,而后点击保留按钮,将用户填写的数据增加到数据库。其时序剖析,如图-15所示:

  1. 服务端要害业务及代码实现

  2. Pojo类定义

  • 业务形容与设计实现

定义长久化对象,封装客户端申请数据,并将数据传递到数据层进行长久化。

  • 要害代码设计与实现

菜单长久层对象类型定义,要害代码如下:

package com.cy.pj.sys.pojo;import lombok.Data;import java.io.Serializable;import java.util.Date;@Datapublic class SysMenu implements Serializable {    private static final long serialVersionUID = -3366721992602387074L;    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;}
  1. DAO接口定义

  • 业务形容与设计实现

负责将用户提交的菜单数据,长久化到数据库。

  • 要害代码设计与实现

在SysMenuDao接口中定义数据长久化办法:

int insertObject(SysMenu entity);
  1. 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>
  1. Service接口定义及实现

  • 业务形容与设计实现

基于管制层申请,调用数据层对象将菜单信息写入到数据库中。

  • 要害代码设计与实现

第一步:在SysMenuService接口中,增加用于保留菜单对象的办法。要害代码如下:

int saveObject(SysMenu entity);

第二步:在SysMenuServiceImpl类中,实现菜单保留操作。要害代码如下:

@Overridepublic 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; }
  1. Controller类定义

  • 业务形容与设计实现

接管客户端提交的菜单数据,并对其进行封装,而后调用业务层对象进行业务解决,最初将业务层处理结果响应到客户端。

  • 要害代码设计与实现

定义Controller办法,借助此办法解决保留菜单数据申请和响应逻辑。要害代码如下:

 @RequestMapping("doSaveObject") public JsonResult doSaveObject(SysMenu entity){ sysMenuService.saveObject(entity); return new JsonRehlt("保留胜利"); }
  1. 客户端要害业务及代码实现

  2. 页面cancel按钮事件处理

  • 业务形容与设计实现

点击页面cancel按钮时,加载菜单那列表页面。

  • 要害代码设计与实现

第一步:事件注册(页面加载实现当前)

 $(".box-footer") .on("click",".btn-cancel",doCancel)

第二步:事件处理函数定义

function doCancel(){ var url="menu/menu_list"; $("#mainContentId").load(url);  }
  1. 页面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; }
  1. 菜单批改页面数据出现

  2. 业务时序剖析

当在菜单列表页面中选中某条记录,而后点击批改按钮时,其业务时序剖析如图-16所示:

  1. 客户端要害业务及代码实现

  2. 列表页面批改按钮事件处理

  • 业务形容与设计实现

点击页面批改按钮时,获取选中菜单记录,并异步加载编辑页面。

  • 要害代码设计与实现

第一步:列表页面批改按钮事件注册,要害代码如下:

$(".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");}
  1. 编辑页面菜单数据出现

  • 业务形容与设计实现

页面加载实现,在页面指定地位出现要批改的数据。

  • 要害代码设计与实现

第一步:页面加载实现当前,获取页面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); }
  1. 菜单数据更新实现

  2. 业务时序剖析

当点击编辑页面更新按钮时,其时序剖析如图-17所示:

  1. 服务端要害业务及代码实现

  2. DAO接口实现

  • 业务形容与设计实现

负责将用户编辑页面提交到服务端的菜单数据,更新到数据库进行持久性存储。

  • 要害代码设计与实现

在SysMenuDao接口中增加数据更新办法,要害代码如下:

int updateObject(SysMenu entity);
  1. 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>
  1. Service接口及实现

  • 业务形容与设计实现

基于管制层申请,对数据进行校验并调用数据层对象将菜单信息更新到数据库中。

  • 要害代码设计与实现

第一步:在SysMenuService接口中,增加用于更新菜单对象的办法。要害代码如下:

int updateObject(SysMenu entity);

第二步:在SysMenuServiceImpl类中,实现菜单保留操作。要害代码如下:

@Overridepublic 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;}
  1. Controller类定义

  • 业务形容与设计实现

接管客户端提交的菜单数据,并对其进行封装,而后调用业务层对象进行业务解决,最初将业务层处理结果响应到客户端。

  • 要害代码设计与实现

定义Controller办法,借助此办法解决保留菜单数据申请和响应逻辑。要害代码如下:

 @RequestMapping("doUpdateObject") public JsonResult doUpdateObject(SysMenu entity){ sysMenuService.updateObject(entity); return new JsonResult("update ok"); }
  1. 客户端要害业务及代码实现

  2. 编辑页面更新按钮事件处理

  • 业务形容与设计实现

点击页面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); } }); }
  1. 总结

  2. 重难点剖析

  • 菜单治理在整个零碎中的定位(资源管理)。
  • 菜单数据的自关联查问实现(查问以后菜单以及这个菜单的上级菜单)。
  • 菜单治理中数据的封装过程(申请数据,响应数据)。
  • 菜单数据在客户端的出现。(treeGrid,zTree)
  1. FAQ剖析

  • 菜单表是如何设计的,都有哪些字段?
  • 菜单列表数据在客户端是如何展现的?(TreeGrid)
  • 菜单删除业务是如何解决的?
  • 菜单编辑页面中上级菜单数据的出现形式?(zTree)
  • 罕用表连贯形式,如图-18所示:

  1. BUG剖析

  • 有效参数异样(IllegalArgumentException),,如图-19所示:


问题剖析:查看以后执行的业务,其后果映射配置,是否将resultType写成了resultMap。

  • 菜单编辑页面,上级菜单树结构出现,如图-20所示:


问题剖析:查看查问后果中是否有parentId,或映射对象Node中parentId是否写错。

  • 属性值注入失败,如图-21所示:


问题剖析:查看Spring容器中是否有SysMenuService接口的实现类对象,因为在SysMenuController中须要一个这样的对象。