前言
由于业务需要,需要涉及到权限管理,故在网上找了很多资料,了解到bootstrap中treeview插件,非常符合我的要求,故此记录所学
在此之前,我们需要这几个插件,
jquery插件下载网址
https://jquery.com/download/
bootstrap treeview插件下载
https://codeload.github.com/jonmiles/bootstrap-treeview/zip/master
效果截图
本地实现的权限树
后台生成数据节点,前台使用,动态生成权限树
本地实现权限树
本地实现源代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="../css/bootstrap.min.css" rel="stylesheet"><!--导入插件,记住必须jquery在bootstrap的js导入之前导入-->
<script type="text/javascript" src="../jquery-3.3.1.js"></script>
<script type="text/javascript" src="../js/bootstrap.min.js"></script>
<!--导入bootstrap treeview插件-->
<link href="../bootstrap-treeview-1.2.0/src/css/bootstrap-treeview.css" rel="stylesheet">
<script type="text/javascript" src="../bootstrap-treeview-1.2.0/src/js/bootstrap-treeview.js"></script>
</head>
<script type="text/javascript">
//以下一段代码是权限树的级联效果,可以直接复制使用
var nodeCheckedSilent = false;
function nodeChecked(event, node) {
if (nodeCheckedSilent) {
return;
}
nodeCheckedSilent = true;
checkAllParent(node);
checkAllSon(node);
nodeCheckedSilent = false;
}
var nodeUncheckedSilent = false;
function nodeUnchecked(event, node) {
if (nodeUncheckedSilent)
return;
nodeUncheckedSilent = true;
uncheckAllParent(node);
uncheckAllSon(node);
nodeUncheckedSilent = false;
}
//选中全部父节点
function checkAllParent(node) {
$('#searchTree').treeview('checkNode', node.nodeId, {
silent: true
});
var parentNode = $('#searchTree').treeview('getParent', node.nodeId);
if (!("nodeId" in parentNode)) {
return;
} else {
checkAllParent(parentNode);
}
}
//取消全部父节点
function uncheckAllParent(node) {
$('#searchTree').treeview('uncheckNode', node.nodeId, {
silent: true
});
var siblings = $('#searchTree').treeview('getSiblings', node.nodeId);
var parentNode = $('#searchTree').treeview('getParent', node.nodeId);
if (!("nodeId" in parentNode)) {
return;
}
var isAllUnchecked = true; //是否全部没选中
for (var i in siblings) {
if (siblings[i].state.checked) {
isAllUnchecked = false;
break;
}
}
if (isAllUnchecked) {
uncheckAllParent(parentNode);
}
}
//级联选中所有子节点
function checkAllSon(node) {
$('#searchTree').treeview('checkNode', node.nodeId, {
silent: true
});
if (node.nodes != null && node.nodes.length > 0) {
for (var i in node.nodes) {
checkAllSon(node.nodes[i]);
}
}
}
//级联取消所有子节点
function uncheckAllSon(node) {
$('#searchTree').treeview('uncheckNode', node.nodeId, {
silent: true
});
if (node.nodes != null && node.nodes.length > 0) {
for (var i in node.nodes) {
uncheckAllSon(node.nodes[i]);
}
}
}
$(function () {
//权限树节点数据
var data = [
{
text: '系统管理',
nodes: [
{
text: '系统用户管理',
nodeid: '11'
},
{
text: '用户角色管理'
},
{
text: '部门管理'
},
{
text: '权限管理'
}
]
},
{
text: '邮件信息管理',
nodes: [
{
text: '邮件基础信息管理'
}
]
},
{
text: '运输系统管理',
nodes: [
{
text: '车辆管理'
},
{
text: '驾驶员管理'
},
{
text: '车辆类型管理'
},
{
text: '车辆驾驶员工作记录管理'
}
]
},
{
text: '段道管理',
nodes: [
{
text: '配送人员管理'
},
{
text: '配送车辆管理'
},
{
text: '配送人员配置管理'
}
]
}, {
text: '配送管理',
nodes: [
{
text: '调整排序'
},
{
text: '邮件分配管理'
},
{
text: '路径规划管理'
},
{
text: '协同配送'
},
{
text: '客户签收管理'
},
{
text: '签收类型管理'
}
]
}
];
$('#searchTree').treeview({//初始化权限树,把节点数据,就是data数据添加到树里面
showCheckbox: true,//确认展示checkbox
data: data,//数据
onNodeChecked: nodeChecked,//当选中节点check时响应函数
onNodeUnchecked: nodeUnchecked//当不选中时响应函数,就是用于级联效果
});
})
</script>
<body class="container">
<h1 class="text-center"><i>hello</i></h1>
<h1 class="text-center"><button class="btn btn-default">提交</button></h1>
<div id="searchTree"></div>
</body>
</html>
复制代码,正确导入插件,会形成上面第一张效果截图
注意事项
其中关于数据data的属性
{
text: "Node 1",//名称
icon: "glyphicon glyphicon-stop",//节点显示的图标
selectedIcon: "glyphicon glyphicon-stop",//节点checked后的图标
color: "#000000",
backColor: "#FFFFFF",
href: "#node-1",
selectable: true,
state: {
checked: true,
disabled: true,
expanded: true,
selected: true
},
tags: ['available'],
nodes: [
{},
...
]
}
更详细的treeview使用信息可以参考这个官网的使用
http://www.jq22.com/jquery-info10461
关于级联
代码可以直接复制,然后名字改一下即可
后台生成权限树节点,前台展示权限树
我们可以参考treeview所需的数据项,treeview插件需要使用json种类的数据项
,我们可以通过实现一个java实体类,来实现自动转换成这样格式的数据,看下面的
复制这段代码,形成一个java类
public class treeNode {
private Integer nodeid;//节点的id,每一个树节点的id,对应插件nodeid属性
private String text;//文本,对应text属性,显示在节点上的文本
private String icon;//对应插件icon属性,列表树节点上的图标,通常是节点左边的图标。,在这里例如glyphicon glyphicon-stop
private String selectedIcon;//对应插件selectIcon属性,当某个节点被选择后显示的图标,通常是节点左边的图标
private String color;//对应color,节点的前景色,覆盖全局的前景色选项。
private String backColor;//对应插件backColor,节点的背景色,覆盖全局的背景色选项。
private String href;//对应插件href属性,结合全局enableLinks选项为列表树节点指定URL
private boolean selectable;//对应selectable属性,指定列表树的节点是否可选择。设置为false将使节点展开,并且不能被选择
private List<treeNode>nodes = new ArrayList<treeNode>();//保存子节点,对应插件中nodes属性
public Integer getNodeid() {
return nodeid;
}
public void setNodeid(Integer nodeid) {
this.nodeid = nodeid;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getSelectedIcon() {
return selectedIcon;
}
public void setSelectedIcon(String selectedIcon) {
this.selectedIcon = selectedIcon;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getBackColor() {
return backColor;
}
public void setBackColor(String backColor) {
this.backColor = backColor;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public boolean isSelectable() {
return selectable;
}
public void setSelectable(boolean selectable) {
this.selectable = selectable;
}
public List<treeNode> getNodes() {
return nodes;
}
public void setNodes(List<treeNode> nodes) {
this.nodes = nodes;
}
@Override
public String toString() {
return "treeNode [nodeid=" + nodeid + ", text=" + text + ", icon=" + icon + ", selectedIcon=" + selectedIcon
+ ", color=" + color + ", backColor=" + backColor + ", href=" + href + ", selectable=" + selectable
+ ", nodes=" + nodes + "]";
}
}
权限树后台代码
可能看不懂,但是其中心思想就是,在后台形成List这样一个集合,每一个treeNode中又包含它自己的子节点,相当于形成了这样的一颗树,就是没有根节点的一棵树。这样返回给前台就是刚好是treeview插件所需要的格式的数据了。我这里返回的是一个Object[]数组,用来保存权限树和当前角色拥有的权限数组
@RequestMapping("/getTree")
@ResponseBody
public Object[] getTree(Integer r_id,HttpSession session){
Object result[] = new Object[2];
List<tb_resource>firstResources = this.roleService.selectResource(-1, 1, null);
List<tb_resource>secondResources = this.roleService.selectResource(-1, 2, null);
List<tb_resource>thirdResources = this.roleService.selectResource(-1, 3, null);
List<treeNode>tree = new ArrayList<treeNode>();
for(int i = 0; i < firstResources.size(); i++) {//循环给第一级节点添加子节点
treeNode node0 = new treeNode();
node0.setText(firstResources.get(i).getRe_name());
node0.setNodeid(firstResources.get(i).getRe_id());
for(tb_resource r : secondResources) {//循环第二级节点,给第一级节点添加子节点
if(node0.getNodeid() == r.getRe_pid()) {//比较第二级节点的父节点id是不是当前父节点的id
treeNode node1 = new treeNode();
node1.setText(r.getRe_name());
node1.setNodeid(r.getRe_id());
for(tb_resource rr : thirdResources) {//循环第三级节点
if(node1.getNodeid() == rr.getRe_pid()) {//比较第三级节点是不是当前第二节节点的子节点
treeNode node2 = new treeNode();
node2.setText(rr.getRe_name());
node2.setNodeid(rr.getRe_id());
node2.setNodes(null);
node1.getNodes().add(node2);
}
}
if(node1.getNodes().size()==0)
node1.setNodes(null);
node0.getNodes().add(node1);
}
}
if(node0.getNodes().size()==0)
node0.setNodes(null);
tree.add(node0);
}
result[0] = tree;
result[1] = this.roleService.selectResourceIdByRoleId(r_id);
return result;
}
权限树前台部分代码
$(function(){
$.ajax({
type:'post',
url:'${pageContext.request.contextPath}/role/getTree',//请求后台的方法得到数据
data:{"r_id":"${role.r_id}"},
dataType:"json",
success:function(result){
$('#searchTree').treeview({
showCheckbox: true,//展示checkbox
data: result[0],//数据
onNodeChecked: nodeChecked,
onNodeUnchecked: nodeUnchecked
});
},
error:function(){
alert("error");
}
});
})
注意事项
节点的实体类的属性名一定要和treeview的属性对应,最好直接复制我写的代码。
前台的部分代码只显示的得到数据和treeview使用数据
总结
实现的效果页面就是上面的那一部分,还有一点就是通过权限check指定的权限,这里我不细说,主要就是同过判断是否有权限,然后check指定的节点即可
最后,感觉结尾有点仓促,可能写的太多了,,,之后有时间在改改