服务器子系统有哪些模块,权限子系统(二)--菜单模块

菜单管理设计说明

业务设计说明

菜单管理又称为资源管理,是系统资源对外的表现形式。本模块主要是实现对菜单进行添加、修改、查询、删除等操作。其表设计语句如下: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='资源管理';

菜单表与角色表是多对多的关系,在表设计时,多对多关系通常由中间表(关系表)进行维护,如图所示:

bVbMuhZ

基于角色菜单表的设计,其角色和菜单对应的关系数据要存储到关系表中,其具体存储形式,如图所示:

bVbMuh0

菜单与角色的关系表脚本设计如下: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),通过静态页面为用户呈现菜单模块的基本需求实现。

当在主页左侧菜单栏,点击菜单管理时,在主页内容呈现区,呈现菜单列表页面,如图所示:

bVbMuh1

当在菜单列表页面点击添加按钮时,异步加载菜单编辑页面,并在列表内容呈现区,呈现菜单编辑页面,如图所示:

bVbMuh5

在菜单编辑页面选择上级菜单时,异步加载菜单信息,并以树结构的形式呈现上级菜单,如图所示:

bVbMuh8

说明:假如客户对此原型进行了确认,后续则可以基于此原型进行研发。

API设计说明

菜单管理业务后台API分层架构及调用关系如图所示:

bVbMuic

说明:分层目的主要将复杂问题简单化,实现各司其职,各尽所能。

菜单管理列表页面呈现

业务时序分析

菜单管理页面的加载过程,其时序分析如图所示:

bVbMuie

1.1 服务端实现

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);

});

}

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

菜单列表页面

▪ 业务描述与设计实现

本页面呈现菜单信息时要以树结构形式进行呈现。此树结构会借助jquery中的treeGrid插件进行实现,所以在菜单列表页面需要引入treeGrid相关JS。但是,具体的treeGrid怎么用可自行在网上进行查询(已比较成熟)。

▪ 关键代码设计与实现:

关键JS引入(menu_list.html),代码如下:

菜单管理列表数据呈现

数据架构分析

菜单列表页面加载完成,启动菜单数据异步加载操作,本次菜单列表页面要呈现菜单以及上级菜单信息,其数据查询时,数据的封装及传递过程,如图所示:

bVbMuif

说明:本模块将从数据库查询到的菜单数据封装到map对象,一行记录一个map对象,其中key为表中的字段(列)名,值为字段(列)对应的值。

数据加载过程其时序分析,如图所示:

bVbMuin

服务端关键业务及代码实现

Dao接口实现

▪ 业务描述及设计实现

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

▪ 关键代码分析及实现

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

public interface SysMenuDao {

}

第二步:在SysMenuDao接口中添加findObjects方法,基于此方法实现菜单数据的查询操作。代码如下:List> findObjects();

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

思考:这里为什么使用map存储数据,有什么优势劣势?

Mapper文件实现

▪ 业务描述及设计实现

基于Dao接口创建映射文件,在此文件中通过相关元素(例如select)描述要执行的数据操作。

▪ 关键代码设计及实现

第一步:在映射文件的设计目录中添加SysMenuMapper.xml映射文件,代码如下:<?xml version=_"1.0"_ encoding=_"UTF-8"_?>

/p>

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

第二步:在映射文件中添加id为findObjects的元素,实现菜单记录查询。我们要查询所有菜单以及菜单对应的上级菜单名称。关键代码如下:

select c.*,(

select p.name

from sys_menus p

where c.parentId=p.id

) parentName

from sys_menus c

说明:自关联查询分析,如图所示:

bVbMuio

Service接口及实现类

▪ 业务描述与设计实现

在菜单查询中,业务层对象主要是借助数据层对象完成菜单数据的查询。后续还可以基于AOP对数据进行缓存,记录访问日志等。

▪ 关键代码设计及实现

第一步:定义菜单业务接口及方法,暴露外界对菜单业务数据的访问,其代码参考如下:package com.cy.pj.sys.service;

import java.util.List;

import java.util.Map;

@Service

public interface SysMenuService {

List> findObjects();

}

第二步:定义菜单业务接口实现类,并添加菜单业务数据对应的查询操作实现,其代码参考如下:package com.cy.pj.sys.service.impl;

import com.cy.pj.sys.dao.SysMenuDao;

import com.cy.pj.sys.service.SysMenuService;

import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

import java.util.Map;

public class SysMenuServiceImpl implements SysMenuService {

@Autowired

private SysMenuDao sysMenuDao;

@Override

public List> findObjects() {

List> list=

sysMenuDao.findObjects();

if(list==null||list.size()==0)

throw new ServiceException("没有对应的菜单信息");

return list;

}

}

第三步:定义业务层异常处理类,封装异常处理,其代码参考如下:package com.cy.pj.common.exception;

public class ServiceException extends RuntimeException{

private static final long serialVersionUID = 5843835376260549700L;

public ServiceException() {

super();

}

public ServiceException(String message) {

super(message);

// TODO Auto-generated constructor stub

}

public ServiceException(Throwable cause) {

super(cause);

// TODO Auto-generated constructor stub

}

}

Controller类实现

▪ 业务描述与设计实现

控制层对象主要负责请求和响应数据的处理,例如,本模块通过业务层对象执行业务逻辑,再通过VO对象封装响应结果(主要对业务层数据添加状态信息),最后将响应结果转换为JSON格式的字符串响应到客户端。

▪ 关键代码设计与实现

定义Controller类,并将此类对象使用Spring框架中的@Controller注解进行标识,表示此类对象要交给Spring管理。然后基于@RequestMapping注解为此类定义根路径映射。代码参考如下:package com.cy.pj.sys.controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping("/menu")

public class SysMenuController {

}

说明:这里的@RestController注解等效于在类上同时添加了@Controller和 @ResponseBody注解.

在Controller类中添加菜单查询处理方法,代码参考如下:@Autowired

private SysMenuService sysMenuService;

@RequestMapping("/doFindObjects")

public JsonResult doFindObjects(){

return new JsonResult(sysMenuService.findObjects());

}

定义全局标准相应类:package com.cy.pj.common.pojo.vo;

import lombok.Data;

import java.io.Serializable;

@Data

public class JsonResult implements Serializable {

private static final long serialVersionUID = -6205785765802397766L;//SysResult/Result/R

/**状态码*/

private int state=1;//1表示SUCCESS,0表示ERROR

/**状态信息*/

private String message="ok";

/**正确数据*/

private Object data;

public JsonResult(){}

/*返回的状态信息*/

public JsonResult(String message) {

this.message = message;

}

/*一般查询时调用,封装查询结果*/

public JsonResult(Object data) {

this.data = data;

}

public JsonResult(Throwable t){

this.state=0;//报错后更改状态码

this.message=t.getMessage();//返回错误信息

}

}

客户端关键业务及代码实现

菜单列表信息呈现

▪ 业务描述与设计实现

菜单页面加载完成以后,向服务端发起异步请求加载菜单信息,当菜单信息加载完成需要将菜单信息呈现到列表页面上。

▪ 关键代码设计与实现

第一步:在菜单列表页面引入treeGrid插件相关的JS。

第二步:在菜单列表页面,定义菜单列表配置信息,关键代码如下: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 '菜单';

}

if (item.type == 2) {

return '按钮';

}

}

},

{

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判断当前菜单是否有子菜单,假如有子菜单则不允许删除,没有则先删除菜单角色关系数据,然后再删除菜单自身信息。其时序分析如图所示:

bVbMuiz

服务端关键业务及代码实现

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"?>

/p>

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

parameterType="int">

delete from sys_role_menus

where menu_id=#{menuId}

第二步:在SysMenuMapper.xml文件中添加基于id统计子菜单数量的元素,关键代码如下:

parameterType="int"

resultType="int">

select count(*)

from sys_menus

where parentId=#{id}

第三步:在SysMenuMapper.xml文件添加delete元素,基于带单id删除菜单自身记录信息,关键代码如下:

delete from sys_menus

where id =#{id}

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;

}

菜单添加页面呈现

业务时序分析

添加页面加载时序分析,如图所示:

bVbMuiA

准备菜单编辑页面

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

菜单编辑页面呈现

▪ 业务描述与设计实现

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

▪ 关键代码设计与实现

第一步:菜单列表页面上,对添加按钮进行事件注册,关键代码如下:$(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);

})

}

菜单编辑页面上级菜单呈现

业务时序分析

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

bVbMuiR

服务端关键业务及代码实现

Node对象

▪ 业务描述与设计实现

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

▪ 关键代码设计与实现package com.cy.pj.common.pojo.vo;

import java.io.Serializable;

public class Node implements Serializable {

private static final long serialVersionUID = -6577397050669133046L;

private Integer id;

private String name;

private Integer parentId;

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getParentId() {

return parentId;

}

public void setParentId(Integer parentId) {

this.parentId = parentId;

}

@Override

public String toString() {

return "Node [id=" + id + ", name=" + name + ", parentId=" + parentId + "]";

}

}

Dao接口实现

▪ 业务描述与设计实现

基于请求获取数据库对应的菜单表中的所有菜单id,name,parentId,一行记录封装为一个Node对象,多个node对象存储到List集合

▪ 关键代码设计与实现

在SysMenuDao接口中添加,用于查询上级菜单相关信息。关键代码如下:List findZtreeMenuNodes();

Mapper映射文件

▪ 业务描述与设计实现

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

▪ 关键代码设计与实现

在SysMenuMapper.xml中添加findZtreeMenuNodes元素,用于查询上级菜单信息。关键代码如下:

resultType="com.cy.pj.common.vo.Node">

select id,name,parentId

from sys_menus

Service接口及实现类

▪ 业务描述与设计实现

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

▪ 关键代码实现

第一步:在SysMenuService接口中,添加查询菜单信息的方法。关键代码如下:List findZtreeMenuNodes();

第二步:在SysMenuServiceImpl类中添加,查询菜单信息方法的实现。关键代码如下:@Override

public List findZtreeMenuNodes() {

return sysMenuDao.findZtreeMenuNodes();

}

Controller类实现

▪ 业务描述与设计实现

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

▪ 关键代码设计与实现@RequestMapping("/doFindZtreeMenuNodes")

public JsonResult doFindZtreeMenuNodes(){

return new JsonResult(

sysMenuService.findZtreeMenuNodes());

}

客户端关键业务及代码实现

ZTree结构定义

▪ 业务描述与设计实现

本模块以开源JS组件方式实现ZTree结构信息的呈现。

▪ 关键代码设计与实现

在menu_edit.html页面中定义用于呈现树结构的DIV组件(假如已有则无需定义)

ZTree数据呈现

▪ 业务描述与设计实现

引入zTree需要的JS,并,并基于JS中的定义的API初始化zTree中的菜单信息。

▪ 关键代码设计与实现

第一步:引入js文件

第二步:在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)

});

菜单数据添加实现

数据基本架构分析

用户在菜单编辑页面输入数据,然后异步提交到服务端,其简易数据传递基本架构,如图所示:

bVbMuiS

用户在菜单添加页面中填写好菜单数据,然后点击保存按钮,将用户填写的数据添加

到数据库。其时序分析,如图所示:

bVbMuiU

服务端关键业务及代码实现

Entity类定义

▪ 业务描述与设计实现

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

▪ 关键代码设计与实现

菜单持久层对象类型定义,关键代码如下:package com.cy.pj.sys.pojo;

import java.io.Serializable;

import java.util.Date;

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;

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getUrl() {

return url;

}

public void setUrl(String url) {

this.url = url;

}

public Integer getType() {

return type;

}

public void setType(Integer type) {

this.type = type;

}

public Integer getSort() {

return sort;

}

public void setSort(Integer sort) {

this.sort = sort;

}

public String getNote() {

return note;

}

public void setNote(String note) {

this.note = note;

}

public Integer getParentId() {

return parentId;

}

public void setParentId(Integer parentId) {

this.parentId = parentId;

}

public String getPermission() {

return permission;

}

public void setPermission(String permission) {

this.permission = permission;

}

public String getCreatedUser() {

return createdUser;

}

public void setCreatedUser(String createdUser) {

this.createdUser = createdUser;

}

public String getModifiedUser() {

return modifiedUser;

}

public void setModifiedUser(String modifiedUser) {

this.modifiedUser = modifiedUser;

}

public Date getCreatedTime() {

return createdTime;

}

public void setCreatedTime(Date createdTime) {

this.createdTime = createdTime;

}

public Date getModifiedTime() {

return modifiedTime;

}

public void setModifiedTime(Date modifiedTime) {

this.modifiedTime = modifiedTime;

}

}

DAO接口定义

▪ 业务描述与设计实现

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

▪ 关键代码设计与实现

在SysMenuDao接口中定义数据持久化方法:int insertObject(SysMenu entity);

Mapper映射文件定义

▪ 业务描述与设计实现

基于SysMenuDao中方法的定义,编写用于实现菜单添加的SQL元素。

▪ 关键代码设计与实现

在SysMenuMapper.xml中添加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})

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 JsonResult ("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;

}

菜单修改页面数据呈现

业务时序分析

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

bVbMuiA

客户端关键业务及代码实现

列表页面修改按钮事件处理

▪ 业务描述与设计实现

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

▪ 关键代码设计与实现

第一步:列表页面修改按钮事件注册,关键代码如下:$(".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);

}

菜单数据更新实现

业务时序分析

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

bVbMui4

服务端关键业务及代码实现

DAO接口实现

▪ 业务描述与设计实现

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

▪ 关键代码设计与实现

在SysMenuDao接口中添加数据更新方法,关键代码如下:int updateObject(SysMenu entity);

Mapper映射文件定义

▪ 业务描述与设计实现

基于SysMenuDao中updateObject方法的定义,编写用于实现菜单更新的SQL元素。

▪ 关键代码设计与实现

在SysMenuMapper.xml中添加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}

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)

▪ 常用表连接方式,如图所示:

bVbMui9

BUG分析

▪ 无效参数异常(IllegalArgumentException),,如图bVbMujc所示:

问题分析:检查当前执行的业务,其结果映射配置,是否将resultType写成了resultMap。

▪ 菜单编辑页面,上级菜单树结构呈现,如图所示:

bVbMujg

问题分析:检查查询结果中是否有parentId,或映射对象Node中parentId是否写错。

▪ 属性值注入失败,如图所示:

bVbMuji

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值