目录
实现步骤:
1. 分析数据库
2. 构建数据源
2.1 编写实体类
2.2 编写节点实体类
2.3 构建BuildTree节点结构方法类
2.4 编写dao类
2.5 编写数据Acntion控制类
3. 前台准备
3.1 配置mvc.xml文件
3.2 页面编写
3.3 运行效果
实现步骤:
1. 分析数据库
如图所示,聪明的你可能发现了!有的数据的属性pid有多个相同的值并且对应了id的值。由此发现它们是有某种关系的,我也不打哑谜了,数据库设计呢,就是把所有一级菜单(最大的菜单)的某一个值设置为一致,这样后来我们只要查询这个值就可以获取所有一级菜单。
这些都是父级内容
pid为10就是id为10下的子菜单!
pid:“所以我们现在是什么关系?”
id:“I'm your father🫰”
2. 构建数据源
2.1 编写实体类
package com.ycxw.entity;/*** 会议系统实体类* * @author 云村小威** @2023年7月11日 下午9:41:18*/
public class Permission {private long id;private String name;private String description;private String url;private long pid;private int ismenu;private long displayno;public Permission() {// TODO Auto-generated constructor stub}public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public long getPid() {return pid;}public void setPid(long pid) {this.pid = pid;}public int getIsmenu() {return ismenu;}public void setIsmenu(int ismenu) {this.ismenu = ismenu;}public long getDisplayno() {return displayno;}public void setDisplayno(long displayno) {this.displayno = displayno;}public Permission(long id, String name, String description, String url, long pid, int ismenu, long displayno) {super();this.id = id;this.name = name;this.description = description;this.url = url;this.pid = pid;this.ismenu = ismenu;this.displayno = displayno;}@Overridepublic String toString() {return "Permission [id=" + id + ", name=" + name + ", description=" + description + ", url=" + url + ", pid="+ pid + ", ismenu=" + ismenu + ", displayno=" + displayno + "]";}}
2.2 编写节点实体类
package com.zking.util;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** * @author 云村小威** @2023年7月12日 上午11:13:05*/
public class TreeVo<T> {/*** 节点ID*/private String id;/*** 显示节点文本*/private String text;/*** 节点状态,open closed*/private Map<String, Object> state;/*** 节点是否被选中 true false*/private boolean checked = false;/*** 节点属性*/private Map<String, Object> attributes;/*** 节点的子节点*/private List<TreeVo<T>> children = new ArrayList<TreeVo<T>>();/*** 父ID*/private String parentId;/*** 是否有父节点*/private boolean hasParent = false;/*** 是否有子节点*/private boolean hasChildren = false;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getText() {return text;}public void setText(String text) {this.text = text;}public Map<String, Object> getState() {return state;}public void setState(Map<String, Object> state) {this.state = state;}public boolean isChecked() {return checked;}public void setChecked(boolean checked) {this.checked = checked;}public Map<String, Object> getAttributes() {return attributes;}public void setAttributes(Map<String, Object> attributes) {this.attributes = attributes;}public List<TreeVo<T>> getChildren() {return children;}public void setChildren(List<TreeVo<T>> children) {this.children = children;}public boolean isHasParent() {return hasParent;}public void setHasParent(boolean isParent) {this.hasParent = isParent;}public boolean isHasChildren() {return hasChildren;}public void setChildren(boolean isChildren) {this.hasChildren = isChildren;}public String getParentId() {return parentId;}public void setParentId(String parentId) {this.parentId = parentId;}public TreeVo(String id, String text, Map<String, Object> state, boolean checked, Map<String, Object> attributes,List<TreeVo<T>> children, boolean isParent, boolean isChildren, String parentID) {super();this.id = id;this.text = text;this.state = state;this.checked = checked;this.attributes = attributes;this.children = children;this.hasParent = isParent;this.hasChildren = isChildren;this.parentId = parentID;}public TreeVo() {super();}}
2.3 构建BuildTree节点结构方法类
package com.zking.util;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author 云村小威** @2023年7月12日 上午11:15:30*/
public class BuildTree {/*** 指定idparam为顶级节点* * @param nodes* @param idParam* @param <T>* @return*/public static <T> List<TreeVo<T>> buildList(List<TreeVo<T>> nodes, String idParam) {if (nodes == null) {return null;}List<TreeVo<T>> topNodes = new ArrayList<TreeVo<T>>();//遍历传过来的节点数据for (TreeVo<T> children : nodes) {//获取父级idString pid = children.getParentId();//如果跟传过来的id相同if (pid == null || idParam.equals(pid)) {//就判定这个父级菜单topNodes.add(children);//继续执行下操作continue;}for (TreeVo<T> parent : nodes) {//获取idString id = parent.getId();//判断父级id是否等于pidif (id != null && id.equals(pid)) {//等于就判定它是谁的儿子parent.getChildren().add(children);//设置是否有父节点和子节点children.setHasParent(true);parent.setChildren(true);continue;}}}return topNodes;}}
2.4 编写dao类
后台方法构建好后,只需将数据源进行Json解析后,进行后台获取输出到页面即可:
package com.ycxw.dao;import java.util.ArrayList;
import java.util.List;import com.ycxw.entity.Permission;
import com.zking.util.BaseDao;
import com.zking.util.BuildTree;
import com.zking.util.PageBean;
import com.zking.util.TreeVo;/*** @author 云村小威** @2023年7月12日 上午11:11:54*/
public class PermissionDao extends BaseDao<Permission>{/*** 获取数据库数据* @param p* @param pageBean* @return* @throws Exception*/public List<Permission> list(Permission p, PageBean pageBean) throws Exception {String sql = "select * from t_oa_permission where 1=1";return super.executeQuery(sql, Permission.class, pageBean);}/*** 将数据库查询的平级数据,转换成有父子关系的数据* @param permission* @param pageBean* @return* @throws Exception*/public List<TreeVo<Permission>> menus(Permission permission, PageBean pageBean) throws Exception{List<TreeVo<Permission>> list = new ArrayList<TreeVo<Permission>>();//获取的数据库集合List<Permission> per = this.list(permission, pageBean);for (Permission p : per) {TreeVo<Permission> vo = new TreeVo<>();//设置节点类内容并添加到节点集合vo.setId(p.getId()+"");//设置节点id vo.setText(p.getName()); //设置节点文本vo.setParentId(p.getPid()+"");//设置父节点list.add(vo);}//返回节点构建好的数据return BuildTree.buildList(list, "-1");}}
2.5 编写数据Acntion控制类
对传入节点进行Json解析,并输出到页面
package demo.web;import java.util.List;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.ycxw.dao.PermissionDao;
import com.ycxw.entity.Permission;
import com.zking.framework.ActionSupport;
import com.zking.framework.ModelDriver;
import com.zking.util.ResponseUtil;
import com.zking.util.TreeVo;
/*** * @author 云村小威** @2023年7月12日 上午11:31:20*/
public class PermissionAction extends ActionSupport implements ModelDriver<Permission> {private Permission permission = new Permission();private PermissionDao dao = new PermissionDao();public void menus(HttpServletRequest req, HttpServletResponse resp) {try {List<TreeVo<Permission>> menus = dao.menus(null, null);//调用封装好的解析json类ResponseUtil.writeJson(resp, menus);} catch (Exception e) {e.printStackTrace();}}@Overridepublic Permission getModel() {return permission;}}
将数据解析成json方法
public static void writeJson(HttpServletResponse response, Object o) throws Exception {ObjectMapper om = new ObjectMapper();// om.writeValueAsString(o)代表了json串write(response, om.writeValueAsString(o));}
3. 前台准备
3.1 配置mvc.xml文件
<action path="/permission" type="demo.web.PermissionAction"></action>
3.2 页面编写
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>主界面</title>
<link rel="stylesheet"href="${pageContext.request.contextPath}/static/js/layui/css/layui.css">
<scriptsrc="${pageContext.request.contextPath}/static/js/layui/layui.js"></script>
</head>
<body>
<div class="layui-layout layui-layout-admin"><div class="layui-header"><div class="layui-logo layui-hide-xs layui-bg-black">layout demo</div><!-- 头部区域(可配合layui 已有的水平导航) --><ul class="layui-nav layui-layout-left"><!-- 移动端显示 --><li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-header-event="menuLeft"><i class="layui-icon layui-icon-spread-left"></i></li><!-- Top导航栏 --><li class="layui-nav-item layui-hide-xs"><a href="">nav 1</a></li><li class="layui-nav-item layui-hide-xs"><a href="">nav 2</a></li><li class="layui-nav-item layui-hide-xs"><a href="">nav 3</a></li><li class="layui-nav-item"><a href="javascript:;">nav groups</a><dl class="layui-nav-child"><dd><a href="">menu 11</a></dd><dd><a href="">menu 22</a></dd><dd><a href="">menu 33</a></dd></dl></li></ul><!-- 个人头像及账号操作 --><ul class="layui-nav layui-layout-right"><li class="layui-nav-item layui-hide layui-show-md-inline-block"><a href="javascript:;"><img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" class="layui-nav-img">tester</a><dl class="layui-nav-child"><dd><a href="">Your Profile</a></dd><dd><a href="">Settings</a></dd><dd><a href="login.jsp">Sign out</a></dd></dl></li><li class="layui-nav-item" lay-header-event="menuRight" lay-unselect><a href="javascript:;"><i class="layui-icon layui-icon-more-vertical"></i></a></li></ul></div><div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul id="menu" class="layui-nav layui-nav-tree" lay-filter="menu"><li class="layui-nav-item layui-nav-itemed"><a class="" href="javascript:;">menu group 1</a><dl class="layui-nav-child"><dd><a href="javascript:;">menu 1</a></dd><dd><a href="javascript:;">menu 2</a></dd><dd><a href="javascript:;">menu 3</a></dd><dd><a href="">the links</a></dd></dl></li><li class="layui-nav-item"><a href="javascript:;">menu group 2</a><dl class="layui-nav-child"><dd><a href="javascript:;">list 1</a></dd><dd><a href="javascript:;">list 2</a></dd><dd><a href="">超链接</a></dd></dl></li><li class="layui-nav-item"><a href="javascript:;">click menu item</a></li><li class="layui-nav-item"><a href="">the links</a></li></ul></div></div><div class="layui-body"><!-- 内容主体区域 --><div style="padding: 15px;">内容主体区域。记得修改 layui.css 和 js 的路径</div></div><div class="layui-footer"><!-- 底部固定区域 -->底部固定区域</div>
</div>
<script>
layui.use(['element', 'layer', 'util'], function(){var element = layui.element,layer = layui.layer,util = layui.util,$ = layui.$;$.post("${pageContext.request.contextPath}/permission.action?methodName=menus",function(data){//将json串转换成数组对象var per = $.parseJSON(data);//拼接左侧导航栏var htmlStr = "";$.each(per,function(i,n){htmlStr+="<li class=\"layui-nav-item layui-nav-itemed\">";htmlStr+="<a class='' href=\"javascript:;\">"+n.text+"</a>";//判断如果子级是否有值if(n.hasChildren){var children = n.children;//遍历子级内容htmlStr+="<dl class=\"layui-nav-child\">";$.each(children,function(i,n){htmlStr+="<dd><a href=\"javascript:;\">"+n.text+"</a></dd>";})htmlStr+="</dl>";}htmlStr+="</li>";})//替换原来标签内容$("#menu").html(htmlStr);//因为要修改之前元素的内容,防止数据出不来需要进行渲染结构传入目标容器的选择器和数据。element.render("menu");
}) });
</script>
</body>
</html>
注意:
防止数据出不来需要进行渲染结构传入目标容器的选择器和数据。
element.render("menu");
3.3 运行效果