java开发过程中遇到的新知识、重点、难点以及出错的解决方法的汇总
1.树形结构的基础知识
1.1节点类型
生成页面上的效果(下面的效果)需要用到zTree插件
约定:整个树形结构节点的层次最多只能有 3 级。
1.2 在数据库表中表示树形结构
在数据库表的记录之间如果没办法建立起父子关系,在页面上显示树形结构就没有依据
1.2.1创建菜单的数据库表
create table t_menu
(
id int(11) not null auto_increment,
pid int(11),
name varchar(200),
url varchar(200),
icon varchar(200),
primary key (id)
);
1.2.2往菜单表中插入数据
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('1',NULL,'系统权限菜单','glyphicon glyphicon-th-list',NULL);
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('2','1',' 控 制 面 板 ','glyphicon glyphicon-dashboard','main.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('3','1','权限管理','glyphicon glyphicon glyphicon-tasks',NULL);
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('4','3',' 用 户 维 护 ','glyphicon glyphicon-user','user/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('5','3',' 角 色 维 护 ','glyphicon glyphicon-king','role/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('6','3',' 菜 单 维 护 ','glyphicon glyphicon-lock','permission/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('7','1',' 业 务 审 核 ','glyphicon glyphicon-ok',NULL);
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('8','7','实名认证审核','glyphicon glyphicon-check','auth_cert/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('9','7',' 广 告 审 核 ','glyphicon glyphicon-check','auth_adv/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('10','7',' 项 目 审 核 ','glyphicon glyphicon-check','auth_project/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('11','1',' 业 务 管 理 ','glyphicon glyphicon-th-large',NULL);
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('12','11',' 资 质 维 护 ','glyphicon glyphicon-picture','cert/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('13','11',' 分 类 管 理 ','glyphicon glyphicon-equalizer','certtype/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('14','11',' 流 程 管 理 ','glyphicon glyphicon-random','process/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('15','11',' 广 告 管 理 ','glyphicon glyphicon-hdd','advert/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('16','11',' 消 息 模 板 ','glyphicon glyphicon-comment','message/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('17','11',' 项 目 分 类 ','glyphicon glyphicon-list','projectType/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('18','11',' 项 目 标 签 ','glyphicon glyphicon-tags','tag/index.htm');
INSERT INTO `t_menu` (`id`, `pid`, `name`, `icon`, `url`) VALUES('19','1',' 参 数 管 理 ','glyphicon glyphicon-list-alt','param/index.htm');
1.2.3关联方式(如何建立父子关系):根节点的 pid 为 null
1.3 在java类中表示树形结构
1.3.1基本方式:在Menu类中使用List<Menu> children 属性存储当前节点的子节点
1.3.2为了配合zTree所需要添加的属性:
- pid属性:找到父节点
- name属性:作为节点的名称
- icon属性:当前节点使用的图标
- open属性:控制节点是否默认打开
- url属性:点击节点时跳转的位置
1.4 按钮增删改查的规则
level 0:根节点
只能添加子节点
level 1:分支节点
修改
添加子节点
没有子节点:可以删除
有子节点:不能删除
level 2:叶子节点
修改
删除
2.1菜单维护:页面显示属性结构
2.1.1目标:将数据库中查询到的数据到页面上显示出来
2.1.2思路:数据库查询全部 → java对象组装 → 页面上使用zTree显示
2.1.3代码:逆向工程生成Menu、MenuExample、MenuMapper、MenuMapper.xml等
对生成的Menu做一些调整:
public Menu() {
}
public Menu(Integer id, Integer pid, String name, String url, String icon, List<Menu> children, Boolean open) {
this.id = id;
this.pid = pid;
this.name = name;
this.url = url;
this.icon = icon;
this.children = children;
this.open = open;
}
//主键
private Integer id;
//父节点的id
private Integer pid;
//节点的名称
private String name;
//节点附带的url地址,是将来点击菜单项要跳转的地址
private String url;
//节点图标的样式
private String icon;
//存储子节点的集合,初始化是为了避免空指针异常
private List<Menu> children = new ArrayList<>();
//控制节点是否默认为打开状态,设置为true表示为默认打开
private Boolean open = true;
2.1.4代码:将数据在 Java 代码中组装成树形结构
MenuServiceImpl中:
@Override
public List<Menu> getAll() {
return menuMapper.selectByExample(new MenuExample());
}
MenuController中:改进前,要改进的原因是存在嵌套遍历,如果循环次数较多,对性能是一个极大的消耗
@ResponseBody
@RequestMapping("/menu/get/whole/tree")
public ResultEntity<Menu> getWholeTreeOld(){
// 1.查询全部的Menu对象
List<Menu> menuList = menuService.getAll();
// 2.声明一个变量用来存储找到的根节点
Menu root = null;
// 3.遍历menuList
for (Menu menu : menuList) {
// 4.获取当前menu对象的pid
Integer pid = menu.getPid();
// 5.检查pid是否为空
if(pid == null){
// 6.把当前正在遍历的这个menu对象复制给root
root = menu;
// 7.停止本次循环,继续执行下一次循环
continue ;
}
// 8.如果pid不为null,说明当前节点有父节点,找到父节点就可以进行组装,建立父子关系
for(Menu maybeFather : menuList){
// 9.获取maybeFather的id属性
Integer id = maybeFather.getId();
// 10.将子节点的pid和疑似父节点的id进行比较
if(Objects.equals(pid,id)){
// 11.将子节点存入父节点的children集合
maybeFather.getChildren().add(menu);
// 12.找到即可停止运行循环
break;
}
}
}
// 13.经过上面的运算,根节点包含了整个树形结构,返回根节点就是返回整个树
return ResultEntity.successWithData(root);
}
MenuController中:改进后
@ResponseBody
@RequestMapping("/menu/get/whole/tree")
public ResultEntity<Menu> getWholeTreeNew(){
// 1.查询全部的Menu对象
List<Menu> menuList = menuService.getAll();
// 2.声明一个变量用来存储找到的根节点
Menu root = null;
// 3.创建Map对象用来存储id和Menu对象的对应关系,便于查找父节点
Map<Integer,Menu> menuMap = new HashMap<>();
// 4.遍历menuList填充menuMap
for (Menu menu : menuList) {
Integer id = menu.getId();
menuMap.put(id,menu);
}
// 5.再次遍历menuList查找根节点,组装父子节点
for (Menu menu : menuList) {
// 6.获取当前menu对象的pid属性值
Integer pid = menu.getPid();
// 7.如果pid为null,判定为根节点
if(pid == null){
root = menu;
// 8.如果当前节点是根节点,那么肯定没有父节点,不必继续执行
continue;
}
// 9.如果pid不为null,说明当前节点有父节点,那么可以根据pid到menuMap中查找对应的Menu对象
Menu father = menuMap.get(pid);
// 10.将当前节点存入父节点的children集合
father.getChildren().add(menu);
}
// 11.经过上面的运算,根节点包含了整个树形结构,返回根节点就是返回整个树
return ResultEntity.successWithData(root);
}
2.1.5代码:跳转页面
<a th:href="@{/menu/to/page}"><i class="glyphicon glyphicon-lock"></i> 菜单维护</a>
<mvc:view-controller path="/menu/to/page" view-name="menu-page"/>
2.1.6引入zTree环境
<link th:href="@{/ztree/zTreeStyle.css}"/>
<script type="text/javascript" th:src="@{/ztree/jquery.ztree.all-3.5.min.js}"></script>
2.1.7 代码:页面上使用 zTree 初步显示树形结构(假数据)
页面效果:
<script type="text/javascript">
$(function () {
// 1.创建 JSON 对象用于存储对 zTree 所做的设置
var setting = {};
// 2.准备生成树形结构的JSON数据
var zNodes =[
{ name:"父节点1 - 展开", open:true,
children: [
{ name:"父节点11 - 折叠",
children: [
{ name:"叶子节点111"},
{ name:"叶子节点112"},
{ name:"叶子节点113"},
{ name:"叶子节点114"}
]},
{ name:"父节点12 - 折叠",
children: [
{ name:"叶子节点121"},
{ name:"叶子节点122"},
{ name:"叶子节点123"},
{ name:"叶子节点124"}
]},
{ name:"父节点13 - 没有子节点", isParent:true}
]},
{ name:"父节点2 - 折叠",
children: [
{ name:"父节点21 - 展开", open:true,
children: [
{ name:"叶子节点211"},
{ name:"叶子节点212"},
{ name:"叶子节点213"},
{ name:"叶子节点214"}
]},
{ name:"父节点22 - 折叠",
children: [
{ name:"叶子节点221"},
{ name:"叶子节点222"},
{ name:"叶子节点223"},
{ name:"叶子节点224"}
]},
{ name:"父节点23 - 折叠",
children: [
{ name:"叶子节点231"},
{ name:"叶子节点232"},
{ name:"叶子节点233"},
{ name:"叶子节点234"}
]}
]},
{ name:"父节点3 - 没有子节点", isParent:true}
];
// 3.初始化树形结构
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
});
</script>
2.1.8 代码:在页面上使用真实数据显示树形结构
<script type="text/javascript">
$(function () {
// 1.准备生成树形结构的 JSON 数据,数据的来源是发送 Ajax 请求得到
$.ajax({
"url":"/menu/get/whole/tree",
"type":"post",
"dataType":"json",
"success":function (response) {
var result = response.operationResult;
if(result == "SUCCESS") {
// 2.创建 JSON 对象用于存储对 zTree 所做的设置
var setting = {};
console.log(response);
// 3.从响应体中获取用来生成树形结构的JSON数据
var zNodes = response.queryData;
// 4.初始化树形结构
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
}
if(result == "FAILED") {
layer.msg("操作失败!"+response.message);
}
},
"error":function(response){
layer.msg(response.status+" "+response.statusText);
}
});
});
</script>
2.1.9 代码:修改默认图标为真实图标代码:修改默认图标为真实图标
menu-page.html中:
<script type="text/javascript" th:src="@{/crowd/my-menu.js}"></script>
// 2.创建 JSON 对象用于存储对 zTree 所做的设置
var setting = {
"view":{
// 每生成一个节点都会调用一下这个函数
"addDiyDom": myAddDiyDom
}
};
my-menu.js中:
// 修改默认的图标
function myAddDiyDom(treeId, treeNode) {
// treeId是整个树形结构附着的ul标签的id:treeDemo
console.log("treeId="+treeId);
// 当前树形节点的全部的数据,包括从后端查询得到的 Menu对象的全部属性
console.log(treeNode);
// zTree 生成 id 的规则
// 例子:treeDemo_7_ico
// 解析:ul标签的id_当前节点的序号_功能
// 提示:"ul标签的id_当前节点的序号"部分可以通过访问 treeNode 的 tId 属性得到
// 根据 id 的生成规则拼接出来 span 标签的 id
var spanId = treeNode.tId + "_ico";
// 根据控制图标的span标签的id找到这个span标签
// 删除旧的class
// 添加新的class
$("#"+spanId).removeClass().addClass(treeNode.icon);
}
2.1.10代码:实现 "点了不跑"
// 2.创建 JSON 对象用于存储对 zTree 所做的设置
var setting = {
//当后台数据只能生成url属性,又不想实现点击节点跳转的功能时,可以直接修改此属性为其他不存在的属性名称
"data":{
// 实现"点了不跑的功能"
"key":{
"url":"notExists"
}
},
"view":{
// 每生成一个节点都会调用一下这个函数
"addDiyDom": myAddDiyDom
}
};
2.1.11代码:显示按钮组
思路:
- 第一步:控制<span>A</span>是否显示
- 第二步:明确具体按钮的添加规则(根据节点的级别)
- 第三步:准备好按钮的 HTML 标签
- 第四步:根据按钮规则把按钮填充到 span 中
menu-page.html中:
"view":{
// 每生成一个节点都会调用一下这个函数
"addDiyDom": myAddDiyDom,
"addHoverDom": myAddHoverDom,
"removeHoverDom": myRemoveHoverDom
}
my-menu.js中:
// 在鼠标移入节点范围时添加按钮组
function myAddHoverDom(treeId, treeNode) {
// 按钮组的标签结构:<span><a><i>按钮</i></a><a><i>按钮</i></a></span>
// 按钮组出现的位置:节点中"treeDemo_节点序号_a"超链接的后面
// 根据 id 的生成规则拼接出来 a超链接 的 id
var anchorId = treeNode.tId + "_a";
// 为了在需要移除按钮组的时候能够精确定位到按钮组所在的span,需要给span设置有规律的id
var btnGroupId = treeNode.tId + "_btnGrp";
// 节点的范围是有一定的区域的,在鼠标移动的过程中可能多次触发添加按钮组事件
// 所以需要判断,每次移入只加一次按钮组
if($("#"+btnGroupId).length > 0){
return;
}
// 准备各个按钮的Html标签
var addBtn = "<a id='"+treeNode.id+"' class='btn btn-info dropdown-toggle btn-xs' style='margin-left:10px;padding-top:0px;' href='#' title='添加子节点'> <i class='fa fa-fw fa-plus rbg '></i></a>";
var removeBtn = "<a id='"+treeNode.id+"' class='btn btn-info dropdown-toggle btn-xs' style='margin-left:10px;padding-top:0px;' href='#' title='删除节点'> <i class='fa fa-fw fa-times rbg '></i></a>";
var editBtn = "<a id='"+treeNode.id+"' class='btn btn-info dropdown-toggle btn-xs' style='margin-left:10px;padding-top:0px;' href='#' title='修改节点'> <i class='fa fa-fw fa-edit rbg '></i></a>";
// 获取当前节点的级别数据
var level = treeNode.level;
// 声明变量存储拼装好的按钮代码
var btnHTML = "";
// 判断当前节点的级别
if(level == 0){
// 级别为 0 时是根节点,只能添加子节点
btnHTML = addBtn;
}
if(level == 1){
// 级别为 1 时是分支节点,可以添加子节点、可以修改,如果没有子节点可以删除
btnHTML = addBtn + " " + editBtn;
// 获取当前节点的子节点数量
var length = treeNode.children.length;
if(length == 0){
btnHTML = btnHTML + " " + removeBtn;
}
}
if(level == 2){
// 级别为 2 时是叶子节点,可以修改和删除
btnHTML = editBtn + " " + removeBtn;
}
// 找到附着按钮组的超链接$("#"+anchorId),找到之后执行在超链接后面附加span元素的操作after
$("#"+anchorId).after("<span id='"+btnGroupId+"'>"+btnHTML+"</span>")
}
// 在鼠标离开节点范围时删除按钮组
function myRemoveHoverDom(treeId, treeNode) {
// 拼接按钮组的id
var btnGroupId = treeNode.tId + "_btnGrp";
// 移除对应的span元素
$("#"+btnGroupId).remove();
}
2.2菜单维护:添加子节点
2.2.1目标:给当前节点添加子节点,保存到数据库并刷新
2.2.2思路:
2.2.3前端代码:
①.引入模态框
模态框的代码以及引入:
<div th:include="modal-menu-add"></div>
<div id="menuAddModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title"> 尚筹网系统弹窗</h4>
</div>
<div class="modal-body">
<form class="form-signin" role="form">
<div class="form-group has-success has-feedback">
节点的pid:<input type="text" name="pid" /><br />
请输入节点名称:<input type="text" name="name" /><br />
请输入URL地址:<input type="text" name="url" /><br />
<i class="glyphicon glyphicon-th-list"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-th-list" />
<i class="glyphicon glyphicon-dashboard"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-dashboard" />
<i class="glyphicon glyphicon glyphicon-tasks"></i>
<input type="radio" name="icon" value="glyphicon glyphicon glyphicon-tasks" />
<i class="glyphicon glyphicon-user"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-user" />
<i class="glyphicon glyphicon-king"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-king" />
<i class="glyphicon glyphicon-lock"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-lock" />
<i class="glyphicon glyphicon-ok"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-ok" />
<i class="glyphicon glyphicon-check"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-check" />
<i class="glyphicon glyphicon-th-large"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-th-large" /> <br />
<i class="glyphicon glyphicon-picture"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-picture" />
<i class="glyphicon glyphicon-equalizer"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-equalizer" />
<i class="glyphicon glyphicon-random"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-random" />
<i class="glyphicon glyphicon-hdd"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-hdd" />
<i class="glyphicon glyphicon-comment"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-comment" />
<i class="glyphicon glyphicon-list"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-list" />
<i class="glyphicon glyphicon-tags"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-tags" />
<i class="glyphicon glyphicon-list-alt"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-list-alt" />
<br />
</div>
</form>
</div>
<div class="modal-footer">
<button id="menuSaveBtn" type="button" class="btn btn-default"><i class="glyphicon glyphicon-plus"></i> 保存</button>
<button id="menuResetBtn" type="reset" class="btn btn-primary"><i class="glyphicon glyphicon-refresh"></i> 重置</button>
</div>
</div>
</div>
</div>
②.给"+"按钮添加class值,用于绑定单击响应函数
//my-menu.js中给"+"按钮添加class:addBtn
var addBtn = "<a id='"+treeNode.id+"' class='btn btn-info dropdown-toggle btn-xs addBtn' style='margin-left:10px;padding-top:0px;' href='#' title='添加子节点'> <i class='fa fa-fw fa-plus rbg '></i></a>";
menu-page.html中:
// 给添加子节点按钮绑定单击响应函数
$("#treeDemo").on("click",".addBtn",function () {
// 打开模态框
$("#menuAddModal").modal("show");
// 将当前节点的id,作为新节点的pid保存到全局变量
window.menuPid = this.id;
// 回显到模态框
$("#menuAddModal [name=pid]").val(menuPid);
// 取消超链接的默认跳转行为
return false;
});
③.给模态框中的" 保存 "按钮绑定单击响应函数
$("#menuSaveBtn").click(function () {
// 收集表单项中用户输入的数据
var name = $.trim($("#menuAddModal [name=name]").val());
var url = $.trim($("#menuAddModal [name=url]").val());
// 单选按钮要定位到被选中的那一个
var icon = $("#menuAddModal [name=icon]:checked").val();
$.ajax({
"url":"/menu/save",
"type":"post",
"data":{
"pid":window.menuPid,
"name":name,
"url":url,
"icon":icon
},
"dataType":"json",
"success":function (response) {
var result = response.operationResult;
if(result == "SUCCESS") {
layer.msg("操作成功!");
// 重新加载树形结构,注意:要在确认服务器端完成保存操作后再刷新,否则有可能刷新不到最新的数据,因为这里是异步的
generateTree();
}
if(result == "FAILED") {
layer.msg("操作失败!"+response.message);
}
},
"error":function (response) {
layer.msg(response.status+" "+response.statusText);
}
});
// 关闭模态框
$("#menuAddModal").modal("hide");
// 清空表单
// jQuery对象调用click()函数,里面不传任何参数,相当于用户点击了一下
$("menuResetBtn").click();
// 清空模态框的内容
$("#menuAddModal [name=pid]").val("");
$("#menuAddModal [name=name]").val("");
$("#menuAddModal [name=url]").val("");
$("#menuAddModal [name=icon]").prop("checked",false);
});
2.2.4后端代码
@ResponseBody
@RequestMapping("/menu/save")
public ResultEntity<String> saveMenu(Menu menu){
menuService.saveMenu(menu);
return ResultEntity.successWithoutData();
}
@Override
public void saveMenu(Menu menu) {
menuMapper.insert(menu);
}
2.3菜单维护:更新节点
2.3.1回显的技巧:zTree提供的功能:只要知道当前节点的一个属性,zTree就可以根据这个属性把节点给搜索出来。在这里我们可以知道节点的id
2.3.2更新的目标:修改当前节点的基本属性,不更换父节点
2.3.3更新的思路:
2.3.4前端代码
①.引入模态框
<div th:include="modal-menu-edit"></div>
<div id="menuEditModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title"> 尚筹网系统弹窗</h4>
</div>
<div class="modal-body">
<form class="form-signin" role="form">
<div class="form-group has-success has-feedback">
节点的id:<input type="text" name="id" /><br />
请输入节点名称:<input type="text" name="name" /><br />
请输入URL地址:<input type="text" name="url" /><br />
<i class="glyphicon glyphicon-th-list"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-th-list" />
<i class="glyphicon glyphicon-dashboard"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-dashboard" />
<i class="glyphicon glyphicon glyphicon-tasks"></i>
<input type="radio" name="icon" value="glyphicon glyphicon glyphicon-tasks" />
<i class="glyphicon glyphicon-user"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-user" />
<i class="glyphicon glyphicon-king"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-king" />
<i class="glyphicon glyphicon-lock"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-lock" />
<i class="glyphicon glyphicon-ok"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-ok" />
<i class="glyphicon glyphicon-check"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-check" />
<i class="glyphicon glyphicon-th-large"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-th-large" /> <br />
<i class="glyphicon glyphicon-picture"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-picture" />
<i class="glyphicon glyphicon-equalizer"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-equalizer" />
<i class="glyphicon glyphicon-random"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-random" />
<i class="glyphicon glyphicon-hdd"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-hdd" />
<i class="glyphicon glyphicon-comment"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-comment" />
<i class="glyphicon glyphicon-list"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-list" />
<i class="glyphicon glyphicon-tags"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-tags" />
<i class="glyphicon glyphicon-list-alt"></i>
<input type="radio" name="icon" value="glyphicon glyphicon-list-alt" />
<br />
</div>
</form>
</div>
<div class="modal-footer">
<button id="menuEditBtn" type="button" class="btn btn-default"><i class="glyphicon glyphicon-edit"></i> 更新</button>
</div>
</div>
</div>
</div>
②.给更新按钮添加class值,用于绑定单击响应函数
// 给更新节点按钮绑定单击响应函数
$("#treeDemo").on("click",".editBtn",function () {
// 打开模态框
$("#menuEditModal").modal("show");
// 得到当前节点的id
window.menuId = this.id;
// 获取zTreeObj对象
var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
// 根据id属性查询节点对象
var currentNode = treeObj.getNodeByParam("id",window.menuId);
// 回显数据到模态框
$("#menuEditModal [name=id]").val(menuId);
$("#menuEditModal [name=name]").val(currentNode.name);
$("#menuEditModal [name=url]").val(currentNode.url);
// radio回显的本质是把value属性和currentNode.icon一致的radio选中
$("#menuEditModal [name=icon]").val([currentNode.icon]);
// 取消超链接的默认跳转行为
return false;
});
③.给模态框中的" 更新 "按钮绑定单击响应函数
// 给更新模态框中的更新按钮绑定单击响应函数
$("#menuEditBtn").click(function () {
// 收集表单项中用户输入的数据
var name = $.trim($("#menuEditModal [name=name]").val());
var url = $.trim($("#menuEditModal [name=url]").val());
// 单选按钮要定位到被选中的那一个
var icon = $("#menuEditModal [name=icon]:checked").val();
$.ajax({
"url":"/menu/update",
"type":"post",
"data":{
"id":window.menuId,
"name":name,
"url":url,
"icon":icon
},
"dataType":"json",
"success":function (response) {
var result = response.operationResult;
if(result == "SUCCESS") {
layer.msg("操作成功!");
// 重新加载树形结构,注意:要在确认服务器端完成保存操作后再刷新,否则有可能刷新不到最新的数据,因为这里是异步的
generateTree();
}
if(result == "FAILED") {
layer.msg("操作失败!"+response.message);
}
},
"error":function (response) {
layer.msg(response.status+" "+response.statusText);
}
});
// 关闭模态框
$("#menuEditModal").modal("hide");
});
2.3.5后端代码
@ResponseBody
@RequestMapping("/menu/update")
public ResultEntity<String> updateMenu(Menu menu){
menuService.updateMenu(menu);
return ResultEntity.successWithoutData();
}
@Override
public void updateMenu(Menu menu) {
// 由于pid没有传入,一定要使用有选择的更新,为了保证pid字段不会被置空
menuMapper.updateByPrimaryKeySelective(menu);
}
2.4菜单维护:删除节点
2.4.1删除的目标:删除当前节点
2.4.2删除的思路:
2.4.3前端代码
①.引入模态框
<div th:include="modal-menu-confirm"></div>
<div id="menuConfirmModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">尚筹网系统弹窗</h4>
</div>
<form>
<div class="modal-body">
您真的要删除<span id="removeNodeSpan"></span>这个节点吗?
</div>
<div class="modal-footer">
<button id="confirmBtn" type="button" class="btn btn-danger"><i class="glyphicon glyphicon-ok"></i> OK</button>
</div>
</form>
</div>
</div>
</div>
②.给删除按钮添加class值,用于绑定单击响应函数
// 给删除的按钮绑定单击响应函数
$("#treeDemo").on("click",".removeBtn",function () {
// 打开模态框
$("#menuConfirmModal").modal("show");
// 得到当前节点的id
window.menuId = this.id;
// 获取zTreeObj对象
var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
// 根据id属性查询节点对象
var currentNode = treeObj.getNodeByParam("id",window.menuId);
// text只能设置文本
// $("#removeNodeSpan").text(currentNode.name);
// 以下更美观
$("#removeNodeSpan").html("【<i class='"+currentNode.icon+"'></i>"+currentNode.name + "】");
});
③.给模态框中的" 删除 "按钮绑定单击响应函数
// 给确认删除模态框中的删除按钮绑定单击响应函数
$("#confirmBtn").click(function () {
$.ajax({
"url":"/menu/delete",
"type":"post",
"data": {
"id":window.menuId
},
"dataType":"json",
"success":function (response) {
var result = response.operationResult;
if(result == "SUCCESS") {
layer.msg("操作成功!");
// 重新加载树形结构,注意:要在确认服务器端完成保存操作后再刷新,否则有可能刷新不到最新的数据,因为这里是异步的
generateTree();
}
if(result == "FAILED") {
layer.msg("操作失败!"+response.message);
}
},
"error":function (response) {
layer.msg(response.status+" "+response.statusText);
}
});
// 关闭模态框
$("#menuConfirmtModal").modal("hide");
});
2.4.4后端代码
@ResponseBody
@RequestMapping("/menu/delete")
public ResultEntity<String> deleteMenu(@RequestParam("id") Integer id){
menuService.deleteMenu(id);
return ResultEntity.successWithoutData();
}
@Override
public void deleteMenu(Integer id) {
menuMapper.deleteByPrimaryKey(id);
}