1. 页面数据呈现
1.1 设计说明
菜单管理又称为资源管理,是系统资源对外的表现形式。本模块主要是实现对菜
单进行添加、修改、查询、删除等操作
1.1.1 数据库说明
1.1.2 多表关系结构图
1.2 原型设计图
1.2.1 首页
1.2.1 添加页面
1.2.2 编辑页面
1.3 服务端实现
1.3.1 时序图分析
1.3.2 编辑PageController
@Controller
public class PageController {
/*
//该代码通用性不够强
@GetMapping("/menu/menu_list")
public String doMenuUI(){
return "sys/menu_list";
}
*/
//通过rest风格的url处理客户端的ui请求
@GetMapping("/{module}/{moduleUI}")
public String doModuleUI(@PathVariable String moduleUI){
return "sys/"+moduleUI;
}
1.3.3 在start.html上编辑点击事件
说明:点击菜单按钮,回显menu_list页面的跳转
<script type="text/javascript">
$(function(){//jQuery中的函数,在页面加载完成之后执行
doLoadUI("load-menu-id", "/menu/menu_list");
})
//实现共性代码封装
function doLoadUI(id,url){//创建点击事件
$("#"+id).click(function(){
//mainContentId指具体页面位置进行异步加载url对应的资源
$("mainContentId").load(url);
})
}
</script>
1.3.4 点击页面实现的效果展示
1.4 菜单列表页面实现
1.4.1 时序图
1.4.2 编辑数据层(SysMenuDao)
package cn.tedu.dbadmin.dao;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
@Mapper
public interface SysMenuDao {
List<Map<String, Object>> findObjects();
}
1.4.3 在Mapper.xml文件中编辑sql语句
<?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="cn.tedu.dbadmin.dao.SysMenuDao">
<!--嵌套查询-->
<select id="findObjects" resultType="map">
select c.*,(select name from sys_menus p where c.parentId = p.id) parenName
from sys_menus c
</select>
<!--表关联查询-->
<!--<select id="findObjects">
select c.*, p.name parentName
from sys_menus c left join sys_menus p on c.parentId = p.id
</select>-->
</mapper>
1.4.4 编辑业务层接口以及实现类(SysMenuServiceImpl)
package cn.tedu.dbadmin.service;
import java.util.List;
import java.util.Map;
public interface SysMenuService {
List<Map<String, Object>> findObjects();
}
package cn.tedu.dbadmin.service;
import cn.tedu.dbadmin.dao.SysMenuDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class SysMenuServiceImpl implements SysMenuService {
@Autowired
private SysMenuDao sysMenuDao;
@Override
public List<Map<String, Object>> findObjects() {
return sysMenuDao.findObjects();
}
}
1.4.5 编辑控制层(Controller)
@RestController
public class SysMenuController {
@Autowired
private SysMenuService sysMenuService;
@GetMapping("/menu/doFindObjects")
public JsonResult doFindObjects() throws InterruptedException {
return new JsonResult(sysMenuService.findObjects());
}
}
1.4.6 页面数据呈现
1.5 实现JQuery中treeGrid
1.5.1 创建web项目,编辑menu-01.html,实现简单跨域访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>The Menu Page</h1>
<table class="table">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>parentName</th>
</tr>
</thead>
<tbody>
<tr><td colspan="3">Data is loading ....</td></tr>
</tbody>
</table>
</div>
<script src="/js/jquery.min.js"></script>
<script>
$(()=>{
doFindObjects();
})
function doFindObjects(){
let url="http://localhost/menu/doFindObjects";
$.get(url,(result)=>{
debugger
//console.log(result);
doHandleQueryResult(result);
})
}
function doHandleQueryResult(result){//JsonResult
if(result.state==1){
doSetTableBodyRows(result.data)
}else{
alert(result.message);
}
}
function doSetTableBodyRows(menus){
//获取tbody对象
let tBody=$("tbody");
//清空tbody中原有内容
tBody.empty();
//将服务端返回的结果更新到页面上
//方法1:
// for(let i=0;i<menus.length;i++) {
// tBody.append(menus[i]);
// }
//方法2
// menus.forEach(function(item){
// tBody.doCreateRow(item)
// })
//方法3
menus.forEach((item)=>{ //箭头函数
tBody.append(doCreateRow(item));
})
}
function doCreateRow(row){
return `<tr>
<td>${row.id}</td>
<td>${row.name}</td>
<td>${row.parentName}</td>
</tr>`
}
</script>
</body>
</html>
1.5.2 引入libs相关js文件
1.5.3 编辑menu-treegrid.html
- 使用Bootstrap
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- 引入CSS/JS -->
<link href="/libs/treegrid/jquery.treegrid.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>The Menu Page</h1>
<table id="menuTable" class="table table-hover">
<thead>
<tr>
<th data-field="selectItem" data-checkbox="true"></th>
</tr>
</thead>
</table>
</div>
<script src="/js/jquery.min.js"></script>
<script type="text/javascript" src="/libs/treegrid/jquery.treegrid.extension.js"></script>
<script type="text/javascript" src="/libs/treegrid/jquery.treegrid.min.js"></script>
<script type="text/javascript" src="/libs/treegrid/tree.table.js"></script>
<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(){
doFindObjects();
})
function doFindObjects(){
let url="http://localhost/menu/doFindObjects";
//构建treeTable对象(第一个参数是用于显示结果的table,第三个参数为列标题)
let treeTable=new TreeTable("menuTable",url,columns);
//初始化treeTable对象
treeTable.init();//底层发送ajax请求
}
</script>
</body>
</html>
2. 删除操作实现
2.1 业务说明
基于用户在列表页面上选择的的菜单记录 ID,执行删除操作,本次删除业务实现中,首先
要基于 id 判断当前菜单是否有子菜单,假如有子菜单则不允许删除,没有则先删除菜单角
色关系数据,然后再删除菜单自身信息。
2.2 时序图
2.3 实现过程
2.3.1 编辑SysRoleMenuDao
package cn.tedu.dbadmin.dao;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysRoleMenuDao {
//基于菜单id删除角色菜单关系
int deleteObjectsByMenuId(Integer id);
}
2.3.2 编辑SysMenuDao
package cn.tedu.dbadmin.dao;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
@Mapper
public interface SysMenuDao {
List<Map<String, Object>> findObjects();
//根据菜单查询子菜单数量
int getChildCount(Integer id);
//基于菜单id删除菜单
int deleteObject(Integer id);
}
2.3.3 编辑SysRoleMenuMapper
<?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="cn.tedu.dbadmin.dao.SysRoleMenuDao">
<delete id="deleteObjectsByMenuId">
delete from sys_role_menus
where #{id} = menu_id
</delete>
</mapper>
2.3.4 编辑SysMenuMapper
<select id="getChildCount" resultType="int">
select count(*) from sys_menus
where parentId = #{id};
</select>
<delete id="deleteObject">
delete from sys_menus
where id = #{id};
</delete>
2.3.5 编辑业务接口和实现类
package cn.tedu.dbadmin.service;
import java.util.List;
import java.util.Map;
public interface SysMenuService {
List<Map<String, Object>> findObjects();
int deleteObject(Integer id);
}
package cn.tedu.dbadmin.service;
import cn.tedu.dbadmin.dao.SysMenuDao;
import cn.tedu.dbadmin.dao.SysRoleMenuDao;
import cn.tedu.dbcommon.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class SysMenuServiceImpl implements SysMenuService {
@Autowired
private SysMenuDao sysMenuDao;
@Autowired
private SysRoleMenuDao sysRoleMenuDao;
@Override
public List<Map<String, Object>> findObjects() {
// List<Map<String, Object>> list = sysMenuDao.findObjects();
// return list;
return sysMenuDao.findObjects();
}
@Override
public int deleteObject(Integer id) {
if(id == null || id < 1){
throw new IllegalArgumentException("请先选择");
}
//查询子菜单数量
int rows = sysMenuDao.getChildCount(id);
if(rows > 1){
throw new ServiceException("请先删除子菜单");
}
//删除角色菜单关系
sysRoleMenuDao.deleteObjectsByMenuId(id);
//删除菜单
int row = sysMenuDao.deleteObject(id);
return row;
}
}
2.3.5 编辑SysMenuController
package cn.tedu.dbadmin.controller;
import cn.tedu.dbadmin.service.SysMenuService;
import cn.tedu.dbcommon.pojo.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/menu/")
@RestController
public class SysMenuController {
@Autowired
private SysMenuService sysMenuService;
@RequestMapping("doFindObjects")
public JsonResult doFindObjects(){
return new JsonResult(sysMenuService.findObjects());
}
@RequestMapping("doDeleteObject")
public JsonResult doDeleteObject(Integer id){
sysMenuService.deleteObject(id);
return new JsonResult("删除成功");
}
}
3. 添加操作实现
3.1 上级菜单数据加载以及实现
3.1.1 定义pojo对象封装查询到的菜单信息
package com.cy.pj.common.pojo;
import lombok.Data;
import java.io.Serializable;
@Data
public class Node implements Serializable {
private static final long serialVersionUID = -7022202313802285223L;
private Integer id;
private String name;
private Integer parentId;
}
3.1.2 编辑SysMenuDao
@Select("select id,name,parentId from sys_menus")
public List<Node> findZtreeMenuNodes();
3.1.3 编辑SysMenuServiceImpl
public List<Node> findZtreeMenuNodes(){
return sysMenuDao.findZtreeMenuNodes();
}
3.1.4 编辑SysMenuController
@GetMapping("/menu/doFindZtreeMenuNodes")
public JsonResult doFindZtreeMenuNodes(){
return new JsonResult(sysMenuService.findZtreeMenuNodes());
}
3.2 客户端树结构呈现shou
3.2.1 框架来源
3.2.2 在web项目中创建menu-ztree.html
说明: 实现树结构菜单的页面呈现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/libs/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css">
</head>
<body>
<!--定义用于显示树结构的div-->
<div>
<ul id="zTreeId" class="ztree"></ul>
</div>
<!--引入ztree需要的js-->
<script src="/js/jquery.min.js"></script>
<script src="/libs/ztree/jquery.ztree.all.min.js"></script>
<script>
//定义ztree的简易配置
var setting = {
data: {
simpleData: {
enable: true,
idKey: "id", //此id对应服务端返回的数据中的id
pIdKey: "parentId",
rootPId: 0
}
}
};//尊重规则
var url="http://localhost/menu/doFindZtreeMenuNodes";
//向服务端发送ajax请求,将响应结果更新到页面上(以ztree结构进行呈现)
$.get(url,function(result){//jsonresult
//初始化zTree对象(参考官方-treejs.cn)-固定写法
$.fn.zTree.init($("#zTreeId"),setting,result.data);
})
</script>
</body>
</html>
3.2.3 页面呈现效果
3.3 添加操作具体实现
3.3.1 时序图
3.3.2 定义SysMenu的pojo类封装添加数据
package cn.tedu.dbcommon.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SysMenu implements Serializable {
private static final long serialVersionUID = 8049305945150183138L;
private Integer id;//菜单id
private String name;//菜单名称
private String url;//菜单URL
private Integer type = 1;
private Integer sort;//菜单序号
private String note;//菜单备注
private Integer parentId;//上级菜单id
private String permission;//授权标识
private String createdUser;//创建用户
private String modifiedUser;//修改用户
private Date createdTime;//创建时间
private Date modifiedTime;//修改时间
}
3.3.3 编辑SysMenuDao
int insertObject(SysMenu menu);
3.3.4 编辑SysMenuMapper
<insert id="insertObject">
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>
3.3.5 编辑SysMenuService
int saveObject(SysMenu entity);
3.3.6 编辑SysMenuServiceImpl
@Override
public int saveObject(SysMenu entity) {
if(entity==null)
throw new IllegalArgumentException("保存对象不能为空");
if(entity.getName()==null||"".equals(entity.getName()))
throw new IllegalArgumentException("菜单名不允许为空");
//........
int rows=sysMenuDao.insertObject(entity);
return rows;
}
3.3.7 编辑SysMenuController
@PostMapping("/menu/doSaveObject")
public JsonResult doSaveObject(SysMenu entity){
sysMenuService.saveObject(entity);
return new JsonResult("save ok");
}
3.3.7 实现效果图
4. 修改操作实现
4.1 时序图
4.2 点击修改实现页面数据呈现
4.3 修改操作实现
4.3.1 SysMenuDao
int updateObject(SysMenu menu);
4.3.2 SysMenuMapper
<update id="updateObject">
update sys_menus
set
name=#{name},
type=#{type},
sort=#{sort},
url=#{url},
parentId=#{parentId},
permission=#{permission},
modifiedUser=#{modifiedUser},
modifiedTime=now()
where id=#{id}
</update>
4.3.3 SysMenuService
int updateObject(SysMenu entity);
4.3.4 SysMenuServiceImpl
@Override
public int updateObject(SysMenu entity) {
if(entity==null)
throw new IllegalArgumentException("保存对象不能为空");
if(entity.getName()==null||"".equals(entity.getName()))
throw new IllegalArgumentException("菜单名不允许为空");
//........
int rows=sysMenuDao.updateObject(entity);
return rows;
}
4.3.5 SysMenuController
@PostMapping("/menu/doUpdateObject")
public JsonResult doUpateObject(SysMenu entity){
sysMenuService.updateObject(entity);
return new JsonResult("update ok");
}
5. Bug总结
- 根据日志提示,在红色框内添加返回结果类型:
- 查看POJO类JsonResult对象是否没有添加@Data注解,即没有get/set/toString方法