使用easyui的tree组件实现给角色快捷分配权限功能

这篇文章主要介绍怎么实现角色权限的快捷分配功能,不需要像大多数项目的授权一样,使用类似穿梭框的组件来授权。

具体实现:通过菜单树的勾选和取消勾选来给角色分配权限,在这之前,需要得到角色的菜单树,角色已有的权限对应树节点的选中状态为true,否则为false。

一、树的格式

首先简单了解一下easyui的tree组件的数据格式

官网截图

402fc4c9bd5e473d8a85505caa04565f.png

 树的json数据格式

    [{
        "id":1,
        "text":"Folder1",
        "iconCls":"icon-save",
        "children":[{
    		"text":"File1",
    		"checked":true
        },{
    		"text":"Books",
    		"state":"open",
    		"attributes":{
    			"url":"/demo/book/abc",
    			"price":100
    		},
    		"children":[{
    			"text":"PhotoShop",
    			"checked":true
    		},{
    			"id": 8,
    			"text":"Sub Bookds",
    			"state":"closed"
    		}]
        }]
    },{
        "text":"Languages",
        "state":"closed",
        "children":[{
    		"text":"Java"
        },{
    		"text":"C#"
        }]
    }]

 

二、创建实体类

根据这个格式,创建一个满足tree组件数据格式要求的实体类,其中attributes属性一般是用不到的,扩展了一个pxh字段,用于实现排序(本篇文章用不到)。

package cn.edu.sgu.www.authority.component;

import lombok.Data;

import java.util.List;

/**
 * easyui树对象
 * @author heyunlin
 * @version 1.0
 */
/*
树的数据格式
    每个节点可以包括下列属性:
        id:节点的 id,它对于加载远程数据很重要。
        text:要显示的节点文本。
        state:节点状态,'open' 或 'closed',默认是 'open'。当设置为 'closed' 时,该节点有子节点,并且将从远程站点加载它们。
        checked:指示节点是否被选中。
        attributes:给一个节点添加的自定义属性。
        children:定义了一些子节点的节点数组。
*/
@Data
public class Tree<T> {
    private String id;

    /**
     * 节点名称
     */
    private String text;

    /**
     * 树节点的展开状态open/closed
     */
    private String state;

    /**
     * 是否被选中
     */
    private boolean checked;

    /**
     * 子树
     */
    private List<Tree<T>> children;

    /**
     * 自定义属性
     */
    T attributes;

    /**
     * 排序号
     */
    private Integer pxh;
}

 

三、获取角色的菜单树

完成分配角色权限的功能之前,需要根据角色的权限生成一个权限树

第一步:查询所有系统权限;

第二步:根据角色ID查询角色拥有的权限;

第三步:遍历所有系统权限生成菜单树,角色拥有的权限,对应树节点选中状态checked属性设置为true;

因为实际保存的是系统中的子权限,即controller接口的所有方法对应的url地址,如:/user/login。

所以在生成树的时候,需要查询父级权限,把父权限的信息设置到树的根结点上。

package cn.edu.sgu.www.authority.service.impl;

import cn.edu.sgu.www.authority.base.Pager;
import cn.edu.sgu.www.authority.component.Tree;
import cn.edu.sgu.www.authority.dto.PermissionTreeDTO;
import cn.edu.sgu.www.authority.entity.Permission;
import cn.edu.sgu.www.authority.entity.RolePermission;
import cn.edu.sgu.www.authority.enums.PermissionType;
import cn.edu.sgu.www.authority.exception.GlobalException;
import cn.edu.sgu.www.authority.mapper.PermissionMapper;
import cn.edu.sgu.www.authority.mapper.RolePermissionMapper;
import cn.edu.sgu.www.authority.pager.RolePermissionPager;
import cn.edu.sgu.www.authority.restful.ResponseCode;
import cn.edu.sgu.www.authority.service.RolePermissionService;
import cn.edu.sgu.www.authority.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author heyunlin
 * @version 1.0
 */
@Service
public class RolePermissionServiceImpl implements RolePermissionService {
    private final PermissionMapper permissionMapper;
    private final RolePermissionMapper rolePermissionMapper;

    public RolePermissionServiceImpl(PermissionMapper permissionMapper, RolePermissionMapper rolePermissionMapper) {
        this.permissionMapper = permissionMapper;
        this.rolePermissionMapper = rolePermissionMapper;
    }
    
    @Override
    public List<Tree<Void>> listTree(Integer roleId) {
        // 查询所有父级权限(权限类型为0),并生成权限ID和权限信息的map
        Map<String, Permission> parentMap = new HashMap<>();
        List<Permission> parentPermissions = permissionMapper.selectByType(PermissionType.FQX.getValue());

        for (Permission permission : parentPermissions) {
            parentMap.put(permission.getId(), permission);
        }

        // 查询角色的权限
        List<Permission> permissions = rolePermissionMapper.selectByRoleId(roleId);
        // 查询全部二级权限(权限类型为1)
        List<Permission> subPermissions = permissionMapper.selectByType(PermissionType.ZQX.getValue());

        // 并根据父级权限ID分组存放到map中
        Map<String, List<Tree<Void>>> listHashMap = new HashMap<>();

        // 遍历,把查询出来的权限按照parentId存到map中
        for (Permission permission : subPermissions) {
            Tree<Void> children = new Tree<>();

            children.setId(permission.getId());
            children.setText(permission.getName());
            children.setChecked(permissions.contains(permission));

            String parentId = permission.getParentId();

            if (listHashMap.containsKey(parentId)) {
                listHashMap.get(parentId).add(children);
            } else {
                listHashMap.put(parentId, new ArrayList<>());
            }
        }

        // 构建返回结果对象
        List<Tree<Void>> trees = new ArrayList<>();

        // 遍历map,生成菜单树
        listHashMap.forEach((key, value) -> {
            Permission parent = parentMap.get(key);

            Tree<Void> tree = new Tree<>();

            tree.setState("open");
            tree.setChildren(value);
            tree.setId(parent.getId());
            tree.setText(parent.getName());

            trees.add(tree);
        });

        return trees;
    }

}

 

四、分配权限功能实现

页面效果图

2ac7acbc91a849ebbdfd862a2cee8e7c.png

当我们勾选树的节点左边的复选框时,会把当前节点的ID添加到数组里,创建两个数组分别存放勾选和取消勾选的树的ID,不要求数组元素唯一,因为在后端去重了(List => Set)。

前端页面的js代码如下:当勾选和取消勾选的是非叶子节点,实际添加到数组中的是该节点下所有的叶子结点。点击对话框的【√确定】按钮时,会把数组的数据提交到后台,当没有选中或者取消选中树节点的时候不提交。

let insertIds = [];
let deleteIds = [];

$(document).ready(function() {
    $("#tree").tree({
		dnd: true,
		animate: true,
		checkbox: true,
		onCheck: function (node, checked) {
			let children = node.children;

			// 父节点点击复选框
			if (children) {
				if (checked) {
					for (let i = 0; i < children.length; i++) {
						insertIds.push(children[i].id);
					}
				} else {
					for (let i = 0; i < children.length; i++) {
						deleteIds.push(children[i].id);
					}
				}
			} else {
				if (checked) {
					insertIds.push(node.id);
				} else {
					deleteIds.push(node.id);
				}
			}
		},
		onContextMenu: function(e, node){
			e.preventDefault();

			$("#tree").tree("select", node.target);
			$("#mm").menu("show", {
				left: e.pageX,
				top: e.pageY
			});
		}
	});

	$("#authorize_dialog").dialog({
		title: "分配角色权限",
		closed: true,
		closable: true,
		draggable: false,
		buttons: [{
			iconCls: "icon-ok",
			text: "确定",
			handler: function() {
				let row = $("#role_list").datalist("getSelected");

				if (row) {
					if (insertIds.length > 0 || deleteIds.length > 0) {
						let data = new FormData();

						data.append("roleId", row.id);

						if (insertIds.length > 0) {
							data.append("insertIds", insertIds);
						}
						if (deleteIds.length > 0) {
							data.append("deleteIds", deleteIds);
						}

						ajaxPost("/role_permission/distribute", data, function (res) {
							insertIds = [];
							deleteIds = [];
							showMsg(res.message);

							$("#tree").tree("reload");
						}, error);
					}
				}

				$("#authorize_dialog").dialog("close");
			}
		}, {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
				$("#authorize_dialog").dialog("close");
			}
		}]
	});

});

 好了,这篇文章就分享到这里了,完整代码可通过下方git地址获取,看完之后如果对你有所帮助,不要忘了点赞+收藏哦~

统一权限平台https://gitee.com/he-yunlin/authority.git

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/52533.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue实现flv格式视频播放

公司项目需要实现摄像头实时视频播放&#xff0c;flv格式的视频。先百度使用flv.js插件实现&#xff0c;但是两个摄像头一个能放一个不能放&#xff0c;没有找到原因。&#xff08;开始两个都能放&#xff0c;后端更改地址后不有一个不能放&#xff09;但是在另一个系统上是可以…

盛元广通实验室教学仪器设备综合信息管理系统LIMS

实验室作为学生以及教师进行科研教学环境&#xff0c;对于实验室设备的使用情况、维护、借还、台账管理、盘点、报废等需要得到有效的管理&#xff0c;以促进科研教学工作的高质量开展&#xff0c;介于传统手动管理方式越发不能满足现代科研的飞速发展需要&#xff0c;实验室的…

使用Django自带的后台管理系统进行数据库管理的实例

Django自带的后台管理系统主要用来对数据库进行操作和管理。它是Django框架的一个强大功能&#xff0c;可以让你快速创建一个管理界面&#xff0c;用于管理你的应用程序的数据模型。 使用Django后台管理系统&#xff0c;你可以轻松地进行以下操作&#xff1a; 数据库管理&…

MySQL高级篇第4章(逻辑架构)

文章目录 1、逻辑架构剖析1.1 服务器处理客户端请求1.2 Connectors1.3 第一层&#xff1a;连接层1.4 第二层&#xff1a;服务层1.5 第三层&#xff1a;引擎层1.6 存储层1.7 小结 2、SQL执行流程2.1 MySQL 中的 SQL执行流程2.2 MySQL8中SQL执行原理2.3 MySQL5.7中SQL执行原理2.4…

分享一个jquery重复绑定事件的问题

这篇文章主要分享一下前端在使用jQuery给元素绑定click事件时遇到的一点小问题。 今天在通过JS代码动态绑定元素的点击事件时遇到一点问题&#xff0c;如上图所示&#xff0c;需要实现动态控制低级内丹格子的解锁&#xff0c;每种宠物造型都有一个内丹数量。如图&#xff0c;忘…

Python Web 开发及 Django 总结

title: Python Web 开发及 Django 总结 date: 2023-07-24 17:26:26 tags: PythonWeb categories:Python cover: https://cover.png feature: false Python 基础部分见&#xff1a;Python 基础总结 1. 创建项目 1.1 命令行 1、下载安装 Django 在终端输入 pip install djan…

【CNN-BiLSTM-attention】基于高斯混合模型聚类的风电场短期功率预测方法(Pythonmatlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【iOS】Frame与Bounds的区别详解

iOS的坐标系 iOS特有的坐标是&#xff0c;是在iOS坐标系的左上角为坐标原点&#xff0c;往右为X正方向&#xff0c;向下为Y正方向。 bounds和frame都是属于CGRect类型的结构体&#xff0c;系统的定义如下&#xff0c;包含一个CGPoint&#xff08;起点&#xff09;和一个CGSiz…

【云原生系列】云计算概念与架构设计介绍

1 什么是云计算 云计算是一种基于互联网的计算模式&#xff0c;在这个模式下&#xff0c;各种计算资源&#xff08;例如计算机、存储设备、网络设备、应用程序等&#xff09;可以通过互联网实现共享和交付。云计算架构设计的主要目标是实现高效、可扩展、可靠、安全和经济的计算…

Spring优雅的在事务提交/回滚前后插入业务逻辑

业务背景 业务那边想要统计下我们这边每天注册商户成功和失败的数量&#xff0c;你看看怎么给他弄下这个功能 功能实现 TransactionSynchronizationManager.registerSynchronization&#xff0c;发现这是spring事务提供的注册回调接口的方法。 在事务注解方法中&#xff0c…

【双评价笔记】农业指向之水资源评价

农业指向水资源单项评价是基于区域内及邻近地区气象站点长时间序列降水观测资料,通过空间插值得到多年平均降水量分布图层,降水量按照200,400,800,1200这个间断点分为好(很湿润),较好(湿润),一般(半湿润),较差(半干旱),差(干旱)5 个等级。 本次实验过程采用的评价分…

婚庆服务小程序app开发方案详解

开发一款婚庆行业服务小程序有哪些功能呢&#xff1f; 1、选择分类 选择婚庆、婚车、婚宴、司仪、彩妆、婚庆用品、跟拍、摄影等&#xff0c;筛选出对应的商家 2、选择商家 选择分类后&#xff0c;可以选择商家&#xff0c;查看各个商家的详细介绍情况。 3、选择服务套餐 各…

mysql主从同步怎么跳过错误

今天介绍两种mysql主从同步跳过错误的方法&#xff1a; 一、两种方法介绍 1、跳过指定数量的事务&#xff1a; mysql>slave stop; mysql>SET GLOBAL SQL_SLAVE_SKIP_COUNTER 1 #跳过一个事务 mysql>slave start2、修改mysql的配置文件&#xff0c;通过slav…

android jetpack DataStore(java)代替SharedPreferences

目录 Preferences DataStore 怎么用&#xff1f;导入依赖创建 Preferences DataStore读取内容写入内容 Proto DataStore怎么用&#xff1f;导入依赖创建proto创建Serializer使用DataStore DataStore 提供两种不同的实现&#xff1a;Preferences DataStore 和 Proto DataStore。…

对各种项目梳理Maven、SpringBoot等介绍

对于maven 项目 首先结束pom.xm依赖库 深入比较几种maven仓库的优先级 Maven与IDEA_idea打包和maven打包区别_快乐搬砖的博客-CSDN博客 pom.xml通过什么下载依赖和驱动呢&#xff1f; 以及maven下的settings.xml <settings xmlns"http://maven.apache.org/SETTIN…

神码ai火车头伪原创设置【php源码】

大家好&#xff0c;给大家分享一下python考什么内容&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 火车头采集ai伪原创插件截图&#xff1a; 1、Python 计算机二级都考什么 Python要到什么程度 考试内容 一、Python语言的基本语法元素…

VsCode与Idea编辑器更换背景图

目录 VsCode Idea VsCode 需要安装background插件 安装完成后&#xff0c;打开设置&#xff0c;搜索background 然后就可以在json文件进行图片设置&#xff0c;透明度等等 Idea 打开File -> Settings 然后找到Appearance &#xff0c; 往下滑&#xff0c;找到BackGround …

聊聊原子弹之父:奥本海默

最近诺兰的电影奥本海默即将热映,其改编自Kai Bird和 Martin J. Sherwin的 2005 年Pulitzer Prize 获奖小说:“American Prometheus: The Triumph and Tragedy of J. Robert Oppenheimer”。这本小说作者研究奥本海默25年,才得以成形,可见奥神本人身上的故事曲折和传奇。 …

从零开始学Docker(三):DockerFile镜像定制

宿主机环境&#xff1a;RockyLinux 9 前言&#xff0c;定制docker镜像的方式有两种&#xff1a; 手动修改容器内容&#xff0c;然后docker commit提交容器为新的镜像通过在dockerfile中定义一系列的命令和参数构成的脚本&#xff0c;然后这些命令应用于基础镜像&#xff0c;依…

C++——模板的作用2:特例化

目录 模板的形式&#xff1a; 一.模板的多参数应用&#xff1a; 例&#xff1a; 错误使用1&#xff1a;使用不标准的模板形参表 ​编辑 错误使用2&#xff1a;使用变量作为实参传递给函数模板 二.模板的特例化&#xff1a; 类模板&#xff1a; 针对模板的特化步骤&am…