菜单管理设计说明

本文详细介绍了菜单管理模块的设计,包括菜单表的创建、菜单与角色的多对多关系处理,以及前端页面的交互设计。菜单管理允许进行增删改查操作,采用树形结构展示,利用jQuery的treeGrid插件进行数据呈现。此外,还涉及到API设计和数据库操作,如自关联查询以获取上级菜单名。服务端和客户端的关键代码实现也进行了说明。
摘要由CSDN通过智能技术生成
  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. 菜单管理列表页面呈现

  1. 业务时序分析

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

  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;

}

  1. 客户端实现

  1. 首页菜单事件处理

  • 业务描述与设计实现

首先准备菜单列表页面(/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引入,代码如下:

<script type="text/javascript" src="bower_components/treegrid/jquery.treegrid.extension.js"></script>

<script type="text/javascript" src="bowe

r_components/treegrid/jquery.treegrid.min.js"></script>

<script type="text/javascript" src="bower_components/treegrid/tree.table.js"></script>

  1. 菜单管理列表数据呈现

  1. 数据架构分析

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

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

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

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

  1. Dao接口实现

  • 业务描述及设计实现

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

  • 关键代码分析及实现

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

@Mapper

public interface SysMenuDao {

}

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

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

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

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

  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;

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

}

  1. 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());

}

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

  1. 菜单列表信息呈现

  • 业务描述与设计实现

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

  • 关键代码设计与实现

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

  1. 业务时序分析

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

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

 

  1. Dao接口实现

  • 业务描述及设计实现

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

  • 关键代码设计及实现

第一步:在创建SysRoleMenuDao并定义基于菜单id删除关系数据的方法,关键代码如下:

@Mapper

public 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相关对象。关键代码如下:

@Autowired

private SysRoleMenuDao sysRoleMenuDao;

第二步:在Sy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值