前言
关于树组件的话,layui官方提供的文档资料不太全面,本篇将分享Tree组件与后台交互实现动态加载数据。
运行效果
老板登录后显示的权限
普通用户显示的权限
Tree组件
1.Tree组件的加载方式
官方文档的基础说明部分可以静下心去仔细看一看(很有必要),我这里采取的非模块加载方式,对应的script的文件引入是layui.all.js
。
注意:script要在写在body底部哦!,不然加载不出来数据。
因为:浏览器生成Dom树的时候是一行一行读HTML代码的,script标签放在最后面就不会影响前面的页面的渲染
这里我用的是ajax来请求后台数据的,而后在success函数中拿到返回的json进行tree控件数据的加载。
1.1选项卡
选项卡的话是配合于tree组件中的点击事件,其中两个核心方法。
- 打开选项卡的方法:
element.tabAdd('tabs',{title:xx,conten:xx})
;
- 判断选项卡的id是否打开过,
$("li[lay-id='" + node.data.id + "']").length
;
<script src="${pageContext.request.contextPath }/static/js/layui/layui.all.js" charset="utf-8"></script>
<script>
;!function(){
//加载所需要的模块
var $=layui.$;
var element = layui.element;
var table = layui.table;
var layer=layui.layer;
var form=layui.form;
var tree = layui.tree;
var url=$("#ctx").val();
layer.msg('酷毙了。。', {icon: 1});
layer.msg(RoleId);
//获取角色权限id
var RoleId= $("#RoleId").val();
//请求tree控件的数据
$.ajax({
type: "post",
url: url+"/permission.action?methodName=menuTree",
dataType: 'json',
data:{rid:RoleId},//获取角色权限id去加载数据
success: function (data) {
tree.render({
elem: '#test13'
,data: data//数据源
,isJump:true//否允许点击节点时弹出新窗口跳转
,spread:true//节点是否初始展开
,showLine: false //是否开启连接线
,click: function (node) {//点击事件
var exist = $("li[lay-id='" + node.data.id + "']").length;//判断是不是用重复的选项卡
if (exist > 0) {
element.tabChange('tabs', node.data.id);// 切换到已有的选项卡
} else {
if (node.data.attributes.self.url != "") {// 判断是否需要新增选项卡
//新增选项卡
element.tabAdd('tabs',
{
title: node.data.title,//获取标题
content: '<iframe scrolling="yes" frameborder="0" src="'+url+node.data.attributes.self.url+'"width="100%" height="100%"></iframe>'
,
id: node.data.id
});
//跳转到指定的选项卡
element.tabChange('tabs', node.data.id);
}
}
}
});
debugger;
}
})
}();
</script>
2.Tree组件的渲染格式
这里可以看到它所提供支持的格式必不可少的有title
和children
属性,如果后台传入的json中没对应上这两个属性的话是出不来想要的效果,而后就是需要绑定元素,和定义数据接口。
3.基础参数
这个是控件里面的基础参数,都比较常用。
4.数据源属性选项
总之定义的json格式属性一定要向下面表中属性对齐。
后台代码实现
1.定义对应数据格式实体
package com.liyingdong.vo;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TreeVo<T> {
/**
* 节点ID
*/
private String id;
/**
* 显示节点标题
*/
private String title;
/**
* 节点状态,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 getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
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 title, 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.title = title;
this.state = state;
this.checked = checked;
this.attributes = attributes;
this.children = children;
this.hasParent = isParent;
this.hasChildren = isChildren;
this.parentId = parentID;
}
public TreeVo() {
super();
}
@Override
public String toString() {
return "TreeVo [id=" + id + ", title=" + title + ", state=" + state + ", checked=" + checked + ", attributes="
+ attributes + ", children=" + children + ", parentId=" + parentId + ", hasParent=" + hasParent
+ ", hasChildren=" + hasChildren + "]";
}
}
2.数据转换
把查询到的数据转换为指定格式。
package com.liyingdong.dao;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.liyingdong.entity.Permission;
import com.liyingdong.util.BaseDao;
import com.liyingdong.util.BuildTree;
import com.liyingdong.util.PageBean;
import com.liyingdong.vo.TreeVo;
public class PermissionDao extends BaseDao<Permission> {
/**
*
* 是直接从数据库获取到的数据
* @param permission
* @param pageBean
* @return
* @throws Exception
*/
public List<Permission> list(Permission permission,String json) throws Exception {
//获取需要包含的字符串
String sql="select * from t_easyui_Permission where id in("+json+") ";
return super.executeQuery(sql, Permission.class, null);
}
public List<TreeVo<Permission>> topNode(String rid,String json) throws Exception {
//查询权限对应的子项
List<Permission> list = this.list(null, json);
//声明顶级容器
List<TreeVo<Permission>> nodes = new ArrayList<TreeVo<Permission>>();
TreeVo<Permission> treeVo = null;
//遍历实现把数据库的结构转换为前端需要的
for (Permission p : list) {
treeVo = new TreeVo<>();
treeVo.setId(p.getId()+"");//id
treeVo.setTitle(p.getName());//标题
treeVo.setParentId(p.getPid()+"");//父id
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put("self", p);//属性
treeVo.setAttributes(attributes);
nodes.add(treeVo);
}
//获取权限对应的数据
return BuildTree.buildList(nodes,nodes.get(0).getParentId());
}
}
3.树结构存储的处理
这个方法是把转换好的数据进行树结构处理,让它用有层次。
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) {
// 获取到当前对象的父id
String pid = children.getParentId();
// 判断id是否等于传进来的父id(根据数据库来判断)
if (pid == null || idParam.equals(pid)) {
// 条件成立加入到当前二级节点下面
topNodes.add(children);
// 跳过
continue;
}
// 内层循环
for (TreeVo<T> parent : nodes) {
// 获取当前对象的id
String id = parent.getId();
// 如果当前对象id等于父id就进来
if (id != null && id.equals(pid)) {
// 获取到二级节点的子节点容器加当前对象
parent.getChildren().add(children);
// 有父节点
children.setHasParent(true);
// 有子节点
parent.setChildren(true);
// 跳过
continue;
}
}
}
// 返回存储好的树结构
return topNodes;
}
角色处理
1.思路
关于角色的权限问题是由中间表来进行判断的,账号表type–》权限表–》主表
我们可以根据登录者的账号来拿到用户的type,然后存入做用域进行跳转到主界面进行ajax请求带type过去type查询权限表拿到结果集进行pid的拼接+逗号的截取,拼接成需要的串后,在进行sql in(截取好的串)查询到数据进行转换返回到前端渲染。
2.PermissionAction
public String menuTree(HttpServletRequest req,HttpServletResponse resp) {
try {
RoleDao roleDao = new RoleDao();
String rid = req.getParameter("rid");
//获取到登录用户的权限id
List<Role> list = roleDao.list(rid, null);
StringBuffer s=new StringBuffer();
//截取需要串
for (Role rl : list) {
s.append(rl.getPid()+",");
}
//截取掉最后一个逗号
int last = s.lastIndexOf(",");
String json = s.toString().substring(0, last);
//sql in包含查询传入的字符串,转为需要的格式输出到浏览器中
ResponseUtil.writeJson(resp, this.pd.topNode(rid, json));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
3.UserDao
public class UserDao extends BaseDao<User>{
public List<User> list(User user) throws Exception {
String sql="select*from t_easyui_user where name='"+user.getName()+"' ";
return super.executeQuery(sql, User.class, null);
}
}
4.RoleDao
public class RoleDao extends BaseDao<Role>{
public List<Role> list(String rid,PageBean pageBean) throws Exception {
String sql1="select *from t_easyui_role_permission where rid="+rid;
return super.executeQuery(sql1, Role.class, pageBean);
}
}
5.UserAction
//登录
public String login(HttpServletRequest req, HttpServletResponse resp) throws Exception {
User u = this.userDao.list(user).get(0);
PrintWriter out = resp.getWriter();
if(u!=null) {
//存入作用域进行转发
req.setAttribute("name",u.getName());
req.setAttribute("pwd", u.getPwd());
req.setAttribute("type", u.getType());
out.print("<script>alert('登录成功!')</script>");
return "index";
}
out.print("<script>alert('账号或者密码错误!!')</script>");
return "login";
}
6.mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/permission" type="com.liyingdong.web.PermissionAction">
</action>
<action path="/book" type="com.liyingdong.web.BookAction">
</action>
<action path="/UserAction" type="com.liyingdong.web.UserAction">
<forward name="index" path="/index.jsp" redirect="false"></forward>
</action>
</config>
7.login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>用户登录</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath }/css/bootstrap.min.css" />
<style>
.form-signin{
width: 400px;
/* 相对定位 :relative 绝对定位:absolute*/
position: relative;
top: 100px;
left: 50%;
margin-left: -200px;
}
</style>
</head>
<body>
<form class="form-signin" action="${pageContext.request.contextPath }/UserAction.action?methodName=login" method="post">
<div class="text-center mb-4">
<img class="mb-4" src="/docs/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">用户登录</h1>
</div>
<div class="form-label-group">
<input type="text" id="name" name="name" class="form-control" placeholder="请输入用户名" required autofocus>
</div>
<div class="form-label-group">
<input type="password" id="pwd" name="pwd" class="form-control" placeholder="请输入密码" required>
</div>
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
<p class="mt-5 mb-3 text-muted text-center">© 2017-2020</p>
</form>
<script src="js/bootstrap.min.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
8.index.jsp
<%@ 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">
<link rel="stylesheet" href="${pageContext.request.contextPath }/static/js/layui/css/layui.css" media="all">
<title>主界面</title>
</head>
<body class="layui-layout-body">
<input type="hidden" id="ctx" value="${pageContext.request.contextPath }" />
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo">东哥的后台</div>
<!-- 头部区域 -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item">
<a href="javascript:;">其它系统</a>
<dl class="layui-nav-child">
<dd><a href="">邮件管理</a></dd>
<dd><a href="">消息管理</a></dd>
<dd><a href="">授权管理</a></dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">
<img src="http://t.cn/RCzsdCq" class="layui-nav-img">
李瀛东
</a>
<dl class="layui-nav-child">
<dd><a href="">基本资料</a></dd>
<dd><a href="">安全设置</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a href="">退出</a></li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域 -->
<div id="test13" class="demo-tree-more"></div>
</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
我是主体区域
<div style="padding: 10px;">
<div class="layui-inline">
</div>
<!-- 选项卡要显示的地方 -->
<div class="layui-body">
<div class="layui-tab" lay-filter="tabs" lay-allowClose="true">
<ul class="layui-tab-title">
</ul>
<div class="layui-tab-content">
数据表格
</div>
</div>
</div>
</div>
<div class="layui-footer">
<!-- 底部固定区域 -->
© layui.com - 底部固定区域
</div>
</div>
<!-- 登录时的账号权限 -->
<input type="hidden" id="RoleId" value="${type}"/>
<script src="${pageContext.request.contextPath }/static/js/layui/layui.all.js" charset="utf-8"></script>
<script>
;!function(){
//加载所需要的模块
var $=layui.$;
var element = layui.element;
var table = layui.table;
var layer=layui.layer;
var form=layui.form;
var tree = layui.tree;
var url=$("#ctx").val();
layer.msg('酷毙了。。', {icon: 1});
layer.msg(RoleId);
//获取角色权限id
var RoleId= $("#RoleId").val();
//请求tree控件的数据
$.ajax({
type: "post",
url: url+"/permission.action?methodName=menuTree",
dataType: 'json',
data:{rid:RoleId},//获取角色权限id去加载数据
success: function (data) {
tree.render({
elem: '#test13'
,data: data//数据源
,isJump:true//否允许点击节点时弹出新窗口跳转
,spread:true//节点是否初始展开
,showLine: false //是否开启连接线
,click: function (node) {//点击事件
var exist = $("li[lay-id='" + node.data.id + "']").length;//判断是不是用重复的选项卡
if (exist > 0) {
element.tabChange('tabs', node.data.id);// 切换到已有的选项卡
} else {
if (node.data.attributes.self.url != "") {// 判断是否需要新增选项卡
//新增选项卡
element.tabAdd('tabs',
{
title: node.data.title,//获取标题
content: '<iframe scrolling="yes" frameborder="0" src="'+url+node.data.attributes.self.url+'"width="100%" height="100%"></iframe>'
,
id: node.data.id
});
//跳转到指定的选项卡
element.tabChange('tabs', node.data.id);
}
}
}
});
debugger;
}
})
}();
</script>
</body>
</html>