尚筹网-菜单维护模块

该博客详细介绍了如何利用Java后端和zTree前端库,构建树形结构数据的展示、菜单维护功能,包括节点类型定义、数据库映射、前端页面引入、数据组装、AJAX交互以及添加、编辑、删除子节点的实现。内容涵盖从数据库查询到页面动态展示,再到用户交互的完整流程。
摘要由CSDN通过智能技术生成

树形结构基础知识

1.节点类型

在这里插入图片描述

在数据库中表示树形结构

在这里插入图片描述

在java类中表示树形结构

1.基本方式
在 Menu 类中使用 List

children 属性存储当前节点的子节点。
2.为配合zTree所需要添加的属性
pid 属性:找到父节点
name 属性:作为节点名称
icon 属性:当前节点使用的图标
open 属性:控制节点是否默认打开
url 属性:点击节点时跳转的位置

2 菜单维护:页面显示树形结构

1 目标

将数据库中查询得到的数据到页面上显示出来。

2.逆向工程

generatorConfig.xml
<table tableName="t_menu" domainObjectName="Menu" />

1.给实体类做些调整

    // 存储子节点的集合,初始化为了避免空指针异常
    private List<Menu> children = new ArrayList<Menu>();
    
    // 控制节点设置为true是否默认为打卡
    private Boolean open = true;
    
    

    public List<Menu> getChildren() {
		return children;
	}

	public void setChildren(List<Menu> children) {
		this.children = children;
	}
	
	public Menu() {
		// TODO Auto-generated constructor stub
	}
	
	

	@Override
	public String toString() {
		return "Menu [id=" + id + ", pid=" + pid + ", name=" + name + ", url=" + url + ", icon=" + icon + ", children="
				+ children + ", open=" + open + "]";
	}

	public Menu(Integer id, Integer pid, String name, String url, String icon, List<Menu> children, Boolean open) {
		super();
		this.id = id;
		this.pid = pid;
		this.name = name;
		this.url = url;
		this.icon = icon;
		this.children = children;
		this.open = open;
	}

2.将数据在 Java 代码中组装成树形结构

serviceIml.java
在这里插入图片描述
`handler.java

@ResponseBody
	@RequestMapping("/menu/get/whole/tree.json")
	public ResultEntity<Menu>  getWholeTree(){
		
		
		        // 1.查询全部的Menu对象
				List<Menu> menuList = menuService.getAll();
				// 2.声明一个变量用来存储中找到哦啊的根节点
				Menu root = null;
				
				// 3.创建一个Map对象来存储id和Menu对象对应关系便于查找父节点
				Map<Integer, Menu> menuMap = new HashMap<Integer, Menu>();
				
				// 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);
				
				}
				// 经过上面运行,根节点包含了整个树形结构,返回根节点就是返回整个树		
		         return ResultEntity.successWithData(root);
	}

3.前端页面的引入

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ZH-cn">
  <%@include file="/WEB-INF/include-head.jsp" %>
  <link rel="stylesheet" href="ztree/zTreeStyle.css">
  <script type="text/javascript" src="ztree/jquery.ztree.all-3.5.min.js"></script>
  <script type="text/javascript" src="crowd/my-menu.js"></script>
  <script type="text/javascript">

  <body>

  <%@include file="/WEB-INF/include-nav.jsp" %>
    <div class="container-fluid">
      <div class="row">
   <%@include file="/WEB-INF/include-sidebar.jsp" %>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
    
     <div class="panel panel-default">
					<div class="panel-heading">
						<i class="glyphicon glyphicon-th-list"></i> 权限菜单列表
						<div style="float: right; cursor: pointer;" data-toggle="modal"
							data-target="#myModal">
							<i class="glyphicon glyphicon-question-sign"></i>
						</div>
					</div>
					<div class="panel-body">
						<!-- 这个ul标签是zTree动态生成的节点所依附的静态节点 -->
						<ul id="treeDemo" class="ztree"></ul>
					</div>
				</div> 
        </div>
      </div>
    </div> 
  </body>
</html>

生成树形结构

发送ajax请求找到刚刚所写的hanler方法去处理,然后返回到页面,引入ztree的css及js,必须在juery之后放,否则无法生效
在这里插入图片描述

 $(function(){
	  
	  // 1.准备生成树形结构的JSON数据,数据的来源是发送Ajax请求得到的
	  $.ajax({
		 "url":"menu/get/whole/tree.json",
		 "type":"post",
		 "dataType":"json",
		 "success":function(response){
			 var result = response.result;
			 if(result =="SUCCESS"){
				 // 2从响应体中获得数据
				 var zNodes = response.data;
				 
				 // 3.创建JSON对象用于存储zTree所做的设置
				  var setting = {
						"view": {
						// 添加数据库里的class显示的图标
							"addDiyDom":myAddDiyDom,
	// 添加鼠标移除上按钮组显示						"addHoverDom":myAddHoverDom,
								"removeHoverDom":
						},
						"data":{
							"key":{
								"url":"huahua"	
							}
						}		 
				 };
				 
				 // 4.进行树形初始化结构
				 $.fn.zTree.init($("#treeDemo"),setting,zNodes);
			 }
			 if(result =="FAILED"){
				 layer.msg(response.message);
			 }
		 }
	  }); 
  });

引入一个外部的js声明一些函数

// 修改默认图标
function myAddDiyDom(treeId,treeNode){
	
	// treeId是整个树形结构附看的ul标签的id
	console.log("treeId="+treeId);
	
	// 当前树形节点的全部的数据,包括从后端得到的menu对象的全部属性
	console.log(treeNode);	
	// zTree生成id的规则,例子:treeDemo_7_ico,解析:ul标签的id_当前节点的序号_功能
	// 提示:"ul标签的id_当前节点的序号"部分可以通过访问treeNode的Id属性得到
	// 根据id的生成规则拼接span的标签的id
	var spanId = treeNode.tId +"_ico";
	
	// 根据控制图标的span标签的id找到这个span标签	
	// 删除旧的class
	// 增加新的class
	$("#"+spanId).removeClass().addClass(treeNode.icon);
}
// 在鼠标移入节点范围内添加按钮组
function myAddHoverDom(treeId,treeNode){
	 // 按钮组的标签结果:<span><a><i></i></a><a><i></i></a></span>
	 // 按钮出现的位置:节点中treeDemo_n_a超链接的后面	
	// 为了在需要移除按钮的时候能够精确定位到按钮所在的span,需要给span设置有规律的id
	var btnGroupId = treeNode.tId + "_btnGrp";
	
	// 判断是否添加过按钮组
	if($("#"+btnGroupId).length>0){
		return ;
	}
	
	// 准备各个按钮的HTML标签
	var addBtn = "<a id='"+treeNode.id+"' class='addBtn btn btn-info dropdown-toggle btn-xs' style='margin-left:10px;padding-top:0px;' href='#' title='添加子节点'>&nbsp;&nbsp;<i class='fa fa-fw fa-plus rbg '></i></a>";
	var removeBtn = "<a id='"+treeNode.id+"' class='removeBtn btn btn-info dropdown-toggle btn-xs' style='margin-left:10px;padding-top:0px;' href='#' title='删除节点'>&nbsp;&nbsp;<i class='fa fa-fw fa-times rbg '></i></a>";
	var editBtn = "<a id='"+treeNode.id+"' class='editBtn btn btn-info dropdown-toggle btn-xs' style='margin-left:10px;padding-top:0px;' href='#' title='修改节点'>&nbsp;&nbsp;<i class='fa fa-fw fa-edit rbg '></i></a>";
	
	// 获取当前节点的级别及判断
	var level = treeNode.level;  
	// 声明变量存储按钮的代码
	var btnHTML ="";
	
	// 判断当前的级别,不同级别有不同的按钮规则,0,只能添加子节点
	if(level == 0){
		btnHTML = addBtn;
	}
	// 1.改名添加删除(仅仅在没有子节点)可以修改
	if(level == 1){
		btnHTML = addBtn +" "+editBtn;
		
		//判断是否有子节点
		var length = treeNode.children.length;
		if(length=0){
			btnHTML = btnHTML+" "+removeBtn;
		}
	}
	
	// 2.编辑删除修改
	if(level == 2){
		btnHTML =editBtn+" "+removeBtn;
	}
	
	
	
	// 找到附着按钮组的超链接
	var anchorId = treeNode.tId + "_a";
	
	// 执行在超链接后面附加span元素的操作
	$("#"+anchorId).after("<span id ='"+btnGroupId+"'>"+btnHTML+"</span>")
	
}

// 在鼠标离开节点范围时删除按钮组
function myRemoveHoverDom(treeId,treeNode){
	
	var btnGroupId = treeNode.tId + "_btnGrp";
	
	// 移除对应的元素
	$("#"+btnGroupId).remove();
}

3菜单维护:添加子节点

给节点添加子节点,然后保存到数据库中并刷新当前树形结构的显示
加入点击后显示增加的模态框(通过juery的on函数通过按钮的class来绑定)
给点击保运绑定函数,然后获得模态框中的数据,以及点击时的id,要将他作为新增的父节点所以要保存到,设置为全局变量,然后得到数据发送ajax请求,后端处理,页面得到响应数据,进行树形结构的重新加载,然后关闭模态框,以及清空刚刚添加节点的模态框中的数据。
前端

$(function(){
	  // 显示分页结构
	  generateTree();
  
	  //给添加子节点按钮绑定点击响应函数
	  $("#treeDemo").on("click",".addBtn",function(){
		  
		  // 将当前节点的id,作为新节点的pid
		  window.pid = this.id;
		   
		  
		  // 打开模态框
		 $("#menuAddModal").modal("show"); 
		 
	  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请求保存数据 
		 $.ajax({
			 "url":"menu/save.json",
		     "type":"post",
		    "data":{
		 "pid":window.pid,
		 "name":name,
		 "url":url,
		 "icon":icon	    	
		    },
		       "dataType":"json",
		    	"success":function(response){
		    		var result = response.result;
		    		
		    		if(result=="SUCCESS"){
		    			
		    			layer.msg("操作成功!");
		    			
		                    generateTree();
		    		}else{
		    			layer.msg("操作成功!"+response.message);
		    		}
	
		    	},
		    	"error":function(response){
		    		layer.msg(response.status+""+response.statusText);
		    		
		    	}
		 	 
		 }); 
		 
 
		// 关闭模态框
		 $("#menuAddModal").modal("hide"); 
		 
		 // 清空表单
		 $("#menuResetBtn").click();
	 }); 
	 
	  
  });
  
handler方法
@ResponseBody
	@RequestMapping("menu/save.json")
	public ResultEntity<String>  saveMenu(Menu menu){
		
		menuService.saveMenu(menu);
		return ResultEntity.successWithoutData();

	}

3菜单维护:更新子节点

查找id,回显表单,进行update,pid还是原来pid,不显示,然后依旧用原来的pid

 //给更新按钮绑定点击响应函数
	  $("#treeDemo").on("click",".editBtn",function(){
		  
		  // 将当前节点的id,保存到全局变量
		  window.id = this.id;		   	  
		  // 打开模态框
		 $("#menuEditModal").modal("show"); 
		  // 获取zTree对象
		  var zTreeObj = $.fn.zTree.getZTreeObj("treeDemo");  
		  // 根据id查找整个属性的值  
		  // 搜索节点的属性名
		  var key = "id";		  
		  // 搜索节点的属性值
		  var value= window.id;  
		 var currentNode =  zTreeObj.getNodeByParam(key,value);
		  
		  // 回显表单数据
		  $("#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 = $("#menuEditModal [name=name]").val();
		  var url = $("#menuEditModal [name=url]").val();
		  
		  // radio回显的本质就是把value的属性和currentNode.icon一致的radio选中
		  var icon = $("#menuEditModal [name=icon]:checked").val();
		  $.ajax({
				 "url":"menu/update.json",
			     "type":"post",
			    "data":{
			 "id":window.id,
			 "name":name,
			 "url":url,
			 "icon":icon	    	
			    },
			       "dataType":"json",
			    	"success":function(response){
			    		var result = response.result;
			    		
			    		if(result=="SUCCESS"){
			    			
			    			layer.msg("操作成功!");
			    			
			                    generateTree();
			    		}else{
			    			layer.msg("操作成功!"+response.message);
			    		}
		
			    	},
			    	"error":function(response){
			    		layer.msg(response.status+""+response.statusText);			    		
			    	}			 	 
			 }); 
			// 关闭模态框
			 $("#menuEditModal").modal("hide"); 
			 
		  
	  });

删除节点

删除与修改比较类似,只需要显示要删除的name就可以,然后在handler方法中,传入要删除的id就可以啦

$("#treeDemo").on("click",".removeBtn",function(){
		  
		  // 将当前节点的id,保存到全局变量
		  window.id = this.id;
		   		  
		  // 打开模态框
		 $("#menuConfirmModal").modal("show"); 		  
		  // 获取zTree对象
		  var zTreeObj = $.fn.zTree.getZTreeObj("treeDemo");	  
		  // 根据id查找整个属性的值  
		  // 搜索节点的属性名
		  var key = "id";		  
		  // 搜索节点的属性值
		  var value= window.id;
	  
		 var currentNode =  zTreeObj.getNodeByParam(key,value);
		  
		  // 回显表单数据
		  $("#removeNodeSpan").html("【<i class='"+currentNode.icon+"'></i>"+currentNode.name+"】");

		  return false;
         }); 
         
         
         $("#confirmBtn").click(function(){
        	 
        	 $.ajax({
				 "url":"menu/remove.json",
			     "type":"post",
			    "data":{
			 "id":window.id
		    	
			    },
			       "dataType":"json",
			    	"success":function(response){
			    		var result = response.result;
			    		
			    		if(result=="SUCCESS"){
			    			
			    			layer.msg("操作成功!");
			    			
			                    generateTree();
			    		}else{
			    			layer.msg("操作成功!"+response.message);
			    		}
		
			    	},
			    	"error":function(response){
			    		layer.msg(response.status+""+response.statusText);
			    		
			    	}
			 	 
			 });
         
        	// 关闭模态框
			 $("#menuConfirmModal").modal("hide"); 
        	 
         });
// handler
@ResponseBody
	@RequestMapping("menu/remove.json")
	public ResultEntity<String>  removeMenu(@RequestParam("id")Integer id){
		
		menuService.removeMenu(id);
		return ResultEntity.successWithoutData();

	}

最终效果
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值