菜单管理列表数据呈现(PROJECT03_DAY01_01)

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

3.1 数据架构分析

菜单列表页面加载完成,启动菜单数据异步加载操作,本次菜单列表页面要呈现菜单以及上级菜单信息,其数据查询时,数据的封装及传递过程,如图-8 所示。
在这里插入图片描述
图-8
说明:本模块将从数据库查询到的菜单数据封装到 map 对象,一行记录一个 map 对象,其中 key 为表中的字段(列)名,值为字段(列)对应的值。

数据加载过程其时序分析,如图-9 所示:
在这里插入图片描述
图-9

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

3.2.1 Dao 接口实现

  • 业务描述及设计实现

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

  • 关键代码分析及实现

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

@Mapper
public interface SysMenuDao {
}

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

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

说明:一行记录映射为一个 map 对象,多行存储到 list。
思考:这里为什么使用 map 存储数据,有什么优势劣势?

3.2.2 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 所示:
在这里插入图片描述
图-10

测试类:

package com.cy.pj.sys.dao;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class SysMenuDaoTests {
	@Autowired
	private SysMenuDao sysMenuDao;
	@Test
	public void testFindObjects() {
		List<Map<String,Object>> list=
		sysMenuDao.findObjects();
		for(Map<String,Object> map:list) {
			System.out.println(map);
		}
		System.out.println(list.size());
	}
}

3.2.3 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() {
	//...
	//...
 	return sysMenuDao.findObjects();
	}
}

3.2.4 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());
}

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

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

4.(课外拓展)菜单管理删除操作实现

4.1 业务时序分析

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

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

4.2.2 Dao 接口实现

  • 业务描述及设计实现

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

  • 关键代码设计及实现

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

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

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

int getChildCount(Integer id);

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

int deleteObject(Integer id);

4.2.3 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>

4.2.4 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;
}

4.2.5 Controller 类实现

  • 业务描述与设计实现

在菜单控制层对象中,添加用于处理菜单删除请求的方法。首先在此方法中通过形参接收客户端提交的数据,然后调用业务层对象执行删除操作,最后封装执行结果,并在运行时将响应对象转换为 JSON 格式的字符串,响应到客户端。

  • 关键代码设计与实现

第一步:在 SysMenuController 中添加用于执行删除业务的方法。代码如下:

@RequestMapping("doDeleteObject")
public JsonResult doDeleteObject(Integer id){
	sysMenuService.deleteObjects(id);
	return new JsonResult("delete ok");
}

第二步:启动 tomcat 进行访问测试,打开浏览器输入如下网址:

http://localhost/menu/doDeleteObject?id=10

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

4.3.1 菜单列表页面事件处理

  • 业务描述及设计实现

用户在页面上首先选择要删除的元素,然后点击删除按钮,将用户选择的记录 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值