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

news2024/11/15 21:37:29

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

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

一、树的格式

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

官网截图

 树的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;
    }

}

四、分配权限功能实现

页面效果图

当我们勾选树的节点左边的对话框时,会把当前节点的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地址获取,看完之后如果对你有所帮助,不要忘了点赞+收藏哦~

统一权限平台icon-default.png?t=N6B9https://gitee.com/he-yunlin/authority.git

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于内核链表和JSON的MQTT的使用

一、内核链表 1.回顾单链表的插入和遍历 假设学生结构体信息如下&#xff0c;封装一个单链表的插入接口和遍历输出的接口&#xff0c;在主函数中利用封装的接口生成一个学生链表&#xff0c;并遍历输出链表的学生信息。 #include <stdio.h> #include <string.h>…

Spring MVC学习笔记,包含mvc架构使用,过滤器、拦截器、执行流程等等

&#x1f600;&#x1f600;&#x1f600;创作不易&#xff0c;各位看官点赞收藏. 文章目录 Spring MVC 习笔记1、Spring MVC demo2、Spring MVC 中常见注解3、数据处理3.1、请求参数处理3.2、响应数据处理 4、RESTFul 风格5、静态资源处理6、HttpMessageConverter 转换器7、过…

iOS开发-下拉刷新动画依次渐隐渐显Indicator指示器效果

iOS开发-下拉刷新动画依次渐隐渐显Indicator指示器效果 之前开发中实现下拉刷新动画三个球依次渐隐渐显指示器效果。 一、效果图 二、基础动画 CABasicAnimation类的使用方式就是基本的关键帧动画。 所谓关键帧动画&#xff0c;就是将Layer的属性作为KeyPath来注册&#xf…

【Linux进程】进程控制(下) {进程程序替换:程序替换的工作原理,程序替换函数exec*,简单的命令行解释器}

四、进程程序替换 之前用fork创建子进程后&#xff0c;父子进程执行同一个程序的不同代码段。 如何使子进程执行另一个不同的程序呢&#xff1f;子进程需要进行程序替换&#xff01; 程序替换&#xff0c;就是通过特定的接口&#xff0c;将磁盘上一个全新的程序&#xff08;包…

STL中的神秘“指针”:迭代器

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;C学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最大…

【Linux】- RPM 与 YUM

RPM 与 YUM 1.1 rpm 包的管理1.2 rpm 包的简单查询指令1.3 rpm 包的其它查询指令&#xff1a;1.4 卸载 rpm 包&#xff1a;2.1 安装 rpm 包3.1 yum3.2 yum 的基本指令3.3 安装指定的 yum 包3.4 yum 应用实例&#xff1a; 1.1 rpm 包的管理 介绍 rpm 用于互联网下载包的打包及安…

SDN系统方法 | 9. 接入网

随着互联网和数据中心流量的爆炸式增长&#xff0c;SDN已经逐步取代静态路由交换设备成为构建网络的主流方式&#xff0c;本系列是免费电子书《Software-Defined Networks: A Systems Approach》的中文版&#xff0c;完整介绍了SDN的概念、原理、架构和实现方式。原文: Softwar…

【Spring Boot丨序列化、反序列化】

序列化、反序列化 概述Jackson 序列化和反序列化简介自定义序列化器注册外部序列化程序&#xff1a; 指定类的 Json 序列化、反序列化 主页传送门&#xff1a;&#x1f4c0; 传送 概述 序列化是将对象转换为字节序列的过程&#xff0c;而反序列化则是将字节序列恢复为对象的过…

用于系统监控及进程管理python库之psutil

前言 对于一个job级别应用再进行测试的过程中&#xff0c;不可避免测试该服务的一些性能&#xff0c;比如占有cpu的使用量&#xff0c;使用的memory的大小等&#xff0c;比较简单的方式是在服务中起一个并行的线程&#xff0c;每隔一段时间打印这些关注量的大小&#xff0c;之后…

【二分答案】CF1661 C

Problem - C - Codeforces 题意&#xff1a; 思路&#xff1a; 在check的时候&#xff0c;我们要尽量用算贡献的思想&#xff0c;并且大胆贪心 Code&#xff1a; #include <bits/stdc.h>#define int long longusing namespace std;const int mxn3e510; const int mxe3…

MySQL基础扎实——列对比运算符是什么

词义解释 在MySQL中&#xff0c;用于进行列对比的运算符主要有以下几种&#xff0c;其实就是逻辑运算符号&#xff1a; 等号&#xff08;&#xff09;&#xff1a;用于判断两个列是否相等&#xff0c;例如&#xff1a;column_name value。 不等号&#xff08;<>或!&am…

Verilog语法学习——边沿检测

边沿检测 代码 module edge_detection_p(input sys_clk,input sys_rst_n,input signal_in,output edge_detected );//存储上一个时钟周期的输入信号reg signal_in_prev;always (posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)signal_in_prev < 0;else…

95. Python基础教程:异常处理try...except语句

【目录】 文章目录 1. try...except语法解析2. 程序异常3. except的4种使用方式3.1 单独的except3.2 except 异常名称3.3 except 异常类型 as 别名3.4 except (异常类型1,异常类型2) as 别名 4. 总结 【正文】 1. try…except语法解析 try[traɪ]&#xff1a;尝试。 except[…

【QT】Day4

1> 思维导图 2> 手动完成服务器的实现&#xff0c;并具体程序要注释清楚 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器类 #include <QTcpSocket> //客户端类 #include <QMessageBox> //…

综合能源系统(4)——综合能源系统建模方法

综合能源系统关键技术与典型案例  何泽家&#xff0c;李德智主编 本文主要从物理、信息、价值三个方面介绍综合能源系统关键技术&#xff0c;如图3-1所示。 物理方面&#xff1a;主要包括综合能源系统建模分析技术、规划设计(配置)技术、优化控制技术、运行维护技术和综合评…

mybatisPlus之逻辑删除解读

目录 为什么会有逻辑删除 逻辑删除基本介绍 逻辑删除的使用 局部使用 全局使用 为什么会有逻辑删除 在我们对数据进行增删查改的时候&#xff0c;对于删除操作来说&#xff0c;我们思考一个问题&#xff0c;在实际开发中我们真的会将数据完成从数据库中删除掉么&#xff1f…

二叉搜索树(二叉排序树)

文章目录 基本概念基本操作实现分析插入数据查找数据删除数据遍历数据 源码 基本概念 二叉搜索树也叫搜索二叉树、二叉排序树、排序二叉树。是一种对查找和排序都有用的特殊二叉树。 二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称BST&#xff09; 如何构建一颗二叉…

【使用维纳滤波进行信号分离】基于维纳-霍普夫方程的信号分离或去噪维纳滤波器估计(Matlab代码实现)

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

【Windows】WDS中如何跳过语言选择以及身份验证

WDS&#xff08;Windows Deployment Services&#xff09;是微软的一项网络服务&#xff0c;用于快速和方便地部署Windows操作系统到多台计算机上。它提供了一种自动化的方式来安装、配置和管理操作系统映像&#xff0c;使企业能够快速部署和更新大量的计算机系统。网上有很多W…

二叉搜索树的本质

引言 打算写写树形数据结构&#xff1a;二叉查找树、红黑树、跳表和 B 树。这些数据结构都是为了解决同一个基本问题&#xff1a;如何快速地对一个大集合执行增删改查。 本篇是第一篇&#xff0c;讲讲搜索树的基础&#xff1a;二叉搜索树。 基本问题 如何在一千万个手机号中…