SpringBoot整合Sa-Token:实现RBAC权限模型

Java系列文章


文章目录

  • Java系列文章
  • 前言
  • 一、基础概念
    • 1.1 RBAC模型核心概念
    • 1.2 Sa-Token核心功能
    • 1.3 环境准备
  • 二、表结构设计
    • 2.1 ER图示例
    • 2.2 数据库表设计
      • 2.2.1 用户表
      • 2.2.2 角色表
      • 2.2.3 部门表
      • 2.2.4 权限表
  • 三、SpringBoot整合Sa-Token
    • 3.1 sa-token基础配置
      • 3.1.1 Maven配置
      • 3.1.2 application.yml
      • 3.1.3 StpUtil鉴权工具类
      • 3.1.4 编写鉴权类
  • 四、RBAC模型设计与实现
    • 4.1 用户管理及登陆实现
      • 4.1.1 定义UserDao类实现接口
      • 4.1.2 配置UserDao.xml映射信息
      • 4.1.3 Service 业务层
      • 4.1.4 Controller Web层
      • 4.1.5 登录返回权限列表
      • 4.1.6 用户分配角色
    • 4.2 角色管理实现
      • 4.2.1 定义RoleDao类实现接口
      • 4.2.2 配置RoleDao.xml映射信息
      • 4.2.3 Service 业务层
      • 4.2.4 Controller Web层
      • 4.2.5 角色分配权限
    • 4.3 部门管理实现
      • 4.31 定义DeptDao类实现接口
      • 4.3.2 配置DeptDao.xml映射信息
      • 4.3.3 Service 业务层
      • 4.3.4 Controller Web层
      • 4.3.5 部门页面编辑
    • 4.4 权限管理实现
      • 4.4.1 定义PermissionDao类实现接口
      • 4.4.2 配置PermissionDao.xml映射信息
      • 4.4.3 Service 业务层
      • 4.4.4 Controller Web层
      • 4.4.5 权限列表编辑


前言

本文将介绍SpringBoot结合sa-token实现RBAC权限模型。


一、基础概念

1.1 RBAC模型核心概念

  • 用户(User)、角色(Role)、权限(Permission)的关系。
  • 模型分层:用户-角色-权限的三层结构。
  • RBAC的基本思想是,对系统操作的各种权限不是直接授予具体的用户,而是在用户集合与权限集合之间建立一个角色集合。每一种角色对应一组相应的权限。一旦用户被分配了适当的角色后,该用户就拥有此角色的所有操作权限。

在这里插入图片描述

1.2 Sa-Token核心功能

  • 登录认证(StpUtil)、权限校验、会话管理、踢人下线等。
  • 关键注解:@SaCheckLogin、@SaCheckRole、@SaCheckPermission。

1.3 环境准备

  • JDK 1.8+、Maven、SpringBoot 2.x。
  • 初始化SpringBoot项目(可通过Spring Initializr生成)。
  • Mysql5.x/8.x

二、表结构设计

2.1 ER图示例

在这里插入图片描述

2.2 数据库表设计

2.2.1 用户表

CREATE TABLE `tb_user` (`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',`username` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '用户名',`password` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '密码',`open_id` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '长期授权字符串',`photo` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '头像网址',`name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '姓名',`sex` enum('男','女') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '性别',`tel` char(11) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '手机号码',`email` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '邮箱',`hiredate` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '入职日期',`role` json DEFAULT NULL COMMENT '角色',`root` tinyint(1) DEFAULT '0' COMMENT '是否是超级管理员',`dept_id` int DEFAULT NULL COMMENT '部门编号',`status` tinyint DEFAULT NULL COMMENT '状态',`create_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=72 DEFAULT CHARSET=utf8mb3 COMMENT='用户表';

2.2.2 角色表

CREATE TABLE `tb_role` (`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`role_name` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色名称',`permissions` json NOT NULL COMMENT '权限集合',`desc` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '描述',`default_permissions` json DEFAULT NULL COMMENT '系统角色内置权限',`systemic` int DEFAULT '0' COMMENT '是否为系统内置角色',`echo` json DEFAULT NULL COMMENT '权限回显集合',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb3 COMMENT='角色表';

2.2.3 部门表

CREATE TABLE `tb_dept` (`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`dept_name` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '部门名称',`tel` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '部门电话',`email` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '部门邮箱',`desc` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '备注',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb3 COMMENT='部门表';

2.2.4 权限表

CREATE TABLE `tb_permission` (`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`parent_id` int DEFAULT NULL COMMENT '父级id',`permission_name` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '权限',`module_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '模块名称',`menu_type` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '菜单类型',`icon` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '菜单图标',`path` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '菜单路由',`create_time` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建时间',`sort` varchar(255) DEFAULT NULL COMMENT '菜单排序',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `unq_permission` (`permission_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=166 DEFAULT CHARSET=utf8mb3 COMMENT='权限表';

三、SpringBoot整合Sa-Token

3.1 sa-token基础配置

3.1.1 Maven配置

<!--SaToken-->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.34.0</version>
</dependency>
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-aop</artifactId><version>1.34.0</version>
</dependency>

3.1.2 application.yml


sa-token:# token 名称(同时也是 cookie 名称)token-name: token# token 有效期(单位:秒) 默认30天,-1 代表永久有效timeout: 2592000# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结active-timeout: -1# 是否允许同一账号多地同时登录 (为 true 时允许一起登录,false 时新登录挤掉旧登录)is-concurrent: true# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token,false 时每次登录新建一个 token)is-share: false# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)token-style: uuid# 是否输出操作日志is-log: false

3.1.3 StpUtil鉴权工具类

StpUtil.login(10001);   // 会话登录
StpUtil.login(10001, "APP");   // 会话登录,并指定设备类型
StpUtil.getTokenValueByLoginId(10001);   // 获取指定账号id的tokenValue 
StpUtil.getTokenValueByLoginId(10001, "PC");   // 获取指定账号id指定设备类型端的tokenValue
StpUtil.getPermissionList();   // 获取:当前账号的权限集合
StpUtil.getPermissionList(10001);   // 获取:指定账号的权限集合 
StpUtil.logout();   // 会话注销 
StpUtil.logout(10001);   // 会话注销,根据账号id
StpUtil.logout(10001, "PC");   // 会话注销,根据账号id 和 设备类型

3.1.4 编写鉴权类

提示:鉴权类是需要我们自己实现的,必须要扩展StpInterface接口才可以。

@Component
class StpInterfaceImpl implements StpInterface {@Resourceprivate UserDao userDao;/*** 返回一个用户所拥有的权限集合*/@Overridepublic List<String> getPermissionList(Object loginId, String loginType) {List<String> list = new ArrayList<>();int userId = Integer.parseInt(loginId.toString());Set<String> set = userDao.searchUserPermissions(userId);list.addAll(set);return list;}/*** 返回一个用户所拥有的角色标识集合*/@Overridepublic List<String> getRoleList(Object loginId, String loginKey) {ArrayList<String> list = new ArrayList();return list;}
}

四、RBAC模型设计与实现

4.1 用户管理及登陆实现

4.1.1 定义UserDao类实现接口

**
* @author lenovo
* @description 针对表【tb_user(用户表)】的数据库操作Mapper
* @createDate 2025-02-06 10:28:09
* @Entity com.example.his.api.db.pojo.UserEntity
*/
public interface UserDao {// 查询用户权限集合public Set<String> searchUserPermissions(int userId);// 查询用户路由限集合public ArrayList<HashMap> searchUserRouterPermissions(int userId);// 查询指定用户public int searchUserById(Map param);// 用户管理-查询分页public ArrayList<HashMap> searchUserByPage(Map param);// 用户管理-新增public int insertUser(Map param);// 用户管理-编辑public int updateUser(Map param);// 用户管理-删除public int deleteUserById(Map param);
}

4.1.2 配置UserDao.xml映射信息

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.his.api.db.dao.UserDao"><resultMap id="BaseResultMap" type="com.example.his.api.db.pojo.UserEntity"><id property="id" column="id" jdbcType="INTEGER"/><result property="username" column="username" jdbcType="VARCHAR"/><result property="password" column="password" jdbcType="VARCHAR"/><result property="openId" column="open_id" jdbcType="VARCHAR"/><result property="photo" column="photo" jdbcType="VARCHAR"/><result property="name" column="name" jdbcType="VARCHAR"/><result property="sex" column="sex" jdbcType="OTHER"/><result property="tel" column="tel" jdbcType="CHAR"/><result property="email" column="email" jdbcType="VARCHAR"/><result property="hiredate" column="hiredate" jdbcType="VARCHAR"/><result property="role" column="role" jdbcType="OTHER"/><result property="root" column="root" jdbcType="TINYINT"/><result property="deptId" column="dept_id" jdbcType="INTEGER"/><result property="status" column="status" jdbcType="TINYINT"/><result property="createTime" column="create_time" jdbcType="VARCHAR"/></resultMap><!-- 查询用户权限集合 --><select id="searchUserPermissions" parameterType="int" resultType="String">SELECT DISTINCT p.permission_nameFROM tb_user uJOIN tb_role r ON JSON_CONTAINS(u.role, CAST(r.id AS CHAR))JOIN tb_permission p ON JSON_CONTAINS(r.permissions, CAST(p.id AS CHAR))WHERE u.id = #{userId}AND u.`status` = 1</select><!-- 查询用户权限列表 --><select id="searchUserRouterPermissions" parameterType="arraylist" resultType="hashmap">SELECT DISTINCT p.module_name as name, p.path, p.iconFROM tb_user uJOIN tb_role r ON JSON_CONTAINS(u.role, CAST(r.id AS CHAR))JOIN tb_permission p ON JSON_CONTAINS(r.permissions, CAST(p.id AS CHAR))WHERE u.id = #{userId}AND u.`status` = 1</select><!-- 查询指定用户 --><select id="searchUserById" parameterType="Map" resultType="integer">select idfrom tb_userwhere username = #{username}and password = #{password}limit 1;</select><!-- 用户管理-查询分页 --><select id="searchUserByPage" parameterType="arraylist" resultType="HashMap">SELECT DISTINCT u.id,u.name,u.sex,u.tel,u.email,d.dept_name AS dept,d.id AS deptId,u.role AS roleId,DATE_FORMAT(u.hiredate,"%Y-%m-%d") AS hiredate,u.root,u.status,(SELECT GROUP_CONCAT( role_name )FROM tb_roleWHERE JSON_CONTAINS ( u.role, CONVERT (id, CHAR) )) AS rolesFROM tb_user uJOIN tb_role r ON JSON_CONTAINS ( u.role, CONVERT (r.id, CHAR) )LEFT JOIN tb_dept d ON u.dept_id = d.id<where><if test="searchKeyWord != null and searchKeyWord != ''">OR d.dept_name LIKE '%${searchKeyWord}%'</if><if test="searchKeyWord != null and searchKeyWord != ''">OR u.name LIKE '%${searchKeyWord}%'</if><if test="searchKeyWord != null and searchKeyWord != ''">OR u.status LIKE '%${searchKeyWord}%'</if><if test="searchKeyWord != null and searchKeyWord != ''">OR u.sex LIKE '%${searchKeyWord}%'</if><if test="searchKeyWord != null and searchKeyWord != ''">OR u.tel LIKE '%${searchKeyWord}%'</if><if test="searchKeyWord != null and searchKeyWord != ''">OR u.email LIKE '%${searchKeyWord}%'</if></where>ORDER BY u.id ASC</select><!-- 用户管理-新增 --><insert id="insertUser">insert into tb_userSETusername=#{username},password=#{password},name=#{name},sex=#{sex},tel=#{tel},email=#{email},status=#{status},dept_id=#{deptId},hiredate=#{hiredate},role=#{role}<if test="openId!=null">,`openId`=#{openId}</if><if test="photo!=null">,`photo`=#{photo}</if><if test="root!=null">,`root`=#{root}</if></insert><!-- 用户管理-编辑 --><update id="updateUser">update tb_userSETname=#{name},sex=#{sex},tel=#{tel},email=#{email},status=#{status},dept_id=#{deptId},hiredate=#{hiredate},role=#{role}<if test="username!=null">,`username`=#{username}</if><if test="password!=null">,`password`=#{password}</if><if test="openId!=null">,`openId`=#{openId}</if><if test="photo!=null">,`photo`=#{photo}</if><if test="root!=null">,`root`=#{root}</if>where id = #{id}</update><!-- 用户管理-删除 --><delete id="deleteUserById">delete from tb_user where id in<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach></delete></mapper>

4.1.3 Service 业务层

@Service
public class UserService {@Resourceprivate UserDao userMapper;// 用户管理-查询idpublic int searchUserById(Map param) {return userMapper.searchUserById(param);}// 用户管理-查询分页public PageInfo<HashMap> searchUserByPage(Map param) {PageHelper.startPage(MapUtil.getInt(param, "pageNum"), MapUtil.getInt(param, "pageSize"));ArrayList<HashMap> list = userMapper.searchUserByPage(param);PageInfo<HashMap> pageInfo = new PageInfo<>(list);return pageInfo;}// 用户管理-新增public int insertUser(Map param) {return userMapper.insertUser(param);}// 用户管理-更新public int updateUser(Map param) {return userMapper.updateUser(param);}// 用户管理-删除public int deleteUserById(Map param) {return userMapper.deleteUserById(param);}// 查询用户路由限集合public ArrayList<HashMap> searchUserRouterPermissions(int userId) {ArrayList<HashMap> routerList = userMapper.searchUserRouterPermissions(userId);ArrayList<HashMap> newRouterList = new ArrayList<>();routerList.forEach(item -> {if(!ObjectUtil.isEmpty(item.get("path"))) {newRouterList.add(item);}});return newRouterList;}
}

4.1.4 Controller Web层

@RestController
@RequestMapping("/admin")
public class UserController {@Resourceprivate UserService userService;@Resourceprivate UserDao userDao;/*** 用户登录* @param form* @return*/@PostMapping("/user/login")public R login(@RequestBody @Valid UserLoginForm form) {Map param = BeanUtil.beanToMap(form);Integer userId = userService.searchUserById(param);if (userId != null) {StpUtil.logout(userId, "Web");// 通过会话对象,向SaToken传递userIdStpUtil.login(userId, "Web");// 生成新的令牌字符串,标记该令牌是给Web端用户使用的String token = StpUtil.getTokenValueByLoginId(userId, "Web");// 获取用户的权限列表List<String> permissionNames = StpUtil.getPermissionList();// 使用 Collections.sort() 排序Collections.sort(permissionNames);// 查询用户路由限集合ArrayList<HashMap> routerList = userService.searchUserRouterPermissions(userId);HashMap map = new HashMap<>();map.put("token", token);map.put("permissionNames", permissionNames);map.put("routerList", routerList);return R.success(map);}return R.error();}/*** 用户管理-查询分页* @param form* @return*/@PostMapping("/user/searchUserByPage")@SaCheckPermission(value = {"SYSTEM:USER:SELECT"}, mode = SaMode.OR)public R searchUserByPage(@RequestBody @Valid UserSearchForm form) {Map param = BeanUtil.beanToMap(form);PageInfo<HashMap> list = userService.searchUserByPage(param);return R.success(list);}/*** 用户管理-编辑* @param form* @return*/@PostMapping("/user/edittUser")@SaCheckPermission(value = {"SYSTEM:USER:EDIT"}, mode = SaMode.OR)public R edittUser(@RequestBody @Valid UserEditForm form) {Map param = BeanUtil.beanToMap(form);param.replace("role", JSONUtil.parseArray(form.getRole()).toString());int rows;if (ObjectUtil.isAllEmpty(param.get("id"))) {rows = userService.insertUser(param);} else {rows = userService.updateUser(param);}return R.success(rows);}/*** 用户管理-删除* @param form* @return*/@PostMapping("/user/deleteUserById")@SaCheckPermission(value = {"SYSTEM:USER:DELETE"}, mode = SaMode.OR)public R deleteUserById(@RequestBody @Valid UserDeleteForm form) {Map param = BeanUtil.beanToMap(form);int rows = userService.deleteUserById(param);return R.success(rows);}
}

4.1.5 登录返回权限列表

用户登陆,会根据当前用户id去关联角色表和权限表,查询对应的权限集合列表。

在这里插入图片描述

4.1.6 用户分配角色

用户管理增删改查实现,并对用户分配不同角色

在这里插入图片描述

4.2 角色管理实现

4.2.1 定义RoleDao类实现接口

/**
* @author lenovo
* @description 针对表【tb_role(角色表)】的数据库操作Mapper
* @createDate 2025-02-06 10:35:25
* @Entity com.example.his.api.db.pojo.RoleEntity
*/
public interface RoleDao {// 角色管理-查询全部public ArrayList<HashMap> searchRoleAll();// 角色管理-查询分页public ArrayList<HashMap> searchRoleByPage(Map param);// 角色管理-新增public int insertRole(Map param);// 角色管理-更新public int updateRole(Map param);// 角色管理-删除public int deleteRole(Map param);
}

4.2.2 配置RoleDao.xml映射信息

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.his.api.db.dao.RoleDao"><resultMap id="BaseResultMap" type="com.example.his.api.db.pojo.RoleEntity"><id property="id" column="id" jdbcType="INTEGER"/><result property="roleName" column="role_name" jdbcType="VARCHAR"/><result property="permissions" column="permissions" jdbcType="OTHER"/><result property="desc" column="desc" jdbcType="VARCHAR"/><result property="defaultPermissions" column="default_permissions" jdbcType="OTHER"/><result property="systemic" column="systemic" jdbcType="INTEGER"/><result property="echo" column="echo" jdbcType="OTHER"/></resultMap><!-- 角色管理-查询全部 --><select id="searchRoleAll" parameterType="arraylist" resultType="hashmap">SELECT id,role_name AS roleName FROM tb_role ORDER BY id</select><!-- 角色管理-查询分页 --><select id="searchRoleByPage" parameterType="arraylist" resultType="hashmap">SELECTr.id,r.role_name AS roleName,COUNT( u.id ) AS users,JSON_LENGTH ( r.permissions ) AS permissionsLength,r.permissions,r.desc,r.systemic,r.echoFROM tb_role rLEFT JOIN tb_user u ON JSON_CONTAINS ( u.role, CONVERT ( r.id, CHAR ) )<where><if test="searchKeyWord != null and searchKeyWord != ''">AND r.role_name LIKE '%${searchKeyWord}%'</if></where>GROUP BY r.idORDER BY r.id</select><!-- 角色管理-新增 --><insert id="insertRole">insert into tb_roleSETrole_name=#{roleName},permissions=#{permissions},echo=#{echo}<if test="desc!=null">,`desc`=#{desc}</if></insert><!-- 角色管理-更新 --><update id="updateRole">update tb_role set`role_name` = #{roleName},`permissions` = #{permissions},`echo` = #{echo}<if test="desc!=null">,`desc`=#{desc}</if><if test="systemic!=null">,`systemic`=#{systemic}</if>where id = #{id}</update><!-- 角色管理-删除 --><delete id="deleteRole">delete from tb_role where id in<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach></delete>
</mapper>

4.2.3 Service 业务层

@Service
public class RoleService {@Resourceprivate RoleDao roleDao;// 角色管理-查询全部public ArrayList<HashMap> searchRoleAll(){return roleDao.searchRoleAll();}// 角色管理-查询分页public PageInfo<HashMap> searchRoleByPage(Map param) {PageHelper.startPage(MapUtil.getInt(param, "pageNum"), MapUtil.getInt(param, "pageSize"));ArrayList<HashMap> roleList = roleDao.searchRoleByPage(param);PageInfo<HashMap> pageInfo = new PageInfo<>(roleList);return pageInfo;}// 角色管理-新增public int insertRole(Map param) {return roleDao.insertRole(param);}// 角色管理-更新public int updateRole(Map param) {return roleDao.updateRole(param);}// 角色管理-删除public int deleteRole(Map param) {return roleDao.deleteRole(param);}
}

4.2.4 Controller Web层

@RestController
@RequestMapping("/admin")
public class RoleController {@Resourceprivate RoleService roleService;/*** 角色管理-查询全部* @return*/@GetMapping("/role/searchRoleAll")@SaCheckPermission(value = {"SYSTEM:ROLE:SELECT"}, mode = SaMode.OR)public R searchRoleAll() {ArrayList<HashMap> roleList = roleService.searchRoleAll();return R.success(roleList);}/*** 角色管理-分页查询* @param form* @return*/@PostMapping("/role/searchRoleByPage")@SaCheckPermission(value = {"SYSTEM:ROLE:SELECT"}, mode = SaMode.OR)public R searchRoleByPage(@RequestBody @Valid RoleSearchForm form) {Map param = BeanUtil.beanToMap(form);PageInfo<HashMap> roleList = roleService.searchRoleByPage(param);return R.success(roleList);}/*** 角色管理-编辑* @param form* @return*/@PostMapping("/role/editRole")@SaCheckPermission(value = {"SYSTEM:ROLE:EDIT"}, mode = SaMode.OR)public R editRole(@RequestBody @Valid RoleEditForm form) {Map param = BeanUtil.beanToMap(form);param.replace("permissions", JSONUtil.parseArray(form.getPermissions()).toString());param.replace("echo", JSONUtil.parseArray(form.getEcho()).toString());int rows;if(ObjectUtil.isEmpty(param.get("id"))) {rows = roleService.insertRole(param);}else {rows = roleService.updateRole(param);}return R.success(rows);}/*** 角色管理-删除* @param form* @return*/@PostMapping("/role/deleteRole")@SaCheckPermission(value = {"SYSTEM:ROLE:DELETE"}, mode = SaMode.OR)public R deleteRole(@RequestBody @Valid RoleDeleteForm form) {Map param = BeanUtil.beanToMap(form);int rows = roleService.deleteRole(param);return R.success(rows);}
}

4.2.5 角色分配权限

在这里插入图片描述

4.3 部门管理实现

4.31 定义DeptDao类实现接口

/**
* @author lenovo
* @description 针对表【tb_dept(部门表)】的数据库操作Mapper
* @createDate 2025-02-10 08:57:44
* @Entity com.example.his.api.db.pojo.DeptEntity
*/
public interface DeptDao {// 部门列表查询public ArrayList<HashMap> searchAllDept();public ArrayList<HashMap> searchDept(Map param);public HashMap searchDeptById(Integer id);// 部门列表新增和编辑public int insertDept(Map param);public int updateDept(Map param);public int deleteBatchDept(Map param);
}

4.3.2 配置DeptDao.xml映射信息

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.his.api.db.dao.DeptDao"><resultMap id="BaseResultMap" type="com.example.his.api.db.pojo.DeptEntity"><id property="id" column="id" jdbcType="INTEGER"/><result property="deptName" column="dept_name" jdbcType="VARCHAR"/><result property="tel" column="tel" jdbcType="VARCHAR"/><result property="email" column="email" jdbcType="VARCHAR"/><result property="desc" column="desc" jdbcType="VARCHAR"/></resultMap><!--  部门列表查询全部  --><select id="searchAllDept" resultMap="BaseResultMap">select * from tb_dept</select><!--  部门列表分页查询  --><select id="searchDept"  resultType="HashMap">selectd.id,d.dept_name as deptName,d.tel,d.email,d.desc,COUNT(u.id) AS emps from tb_dept d left join tb_user u on u.dept_id = d.id<where><if test="searchKeyWord != null and searchKeyWord != ''">1 = 1AND d.dept_name like "%${searchKeyWord}%"OR d.tel = #{searchKeyWord}OR d.email = #{searchKeyWord}OR d.desc like "%${searchKeyWord}%"</if></where>GROUP BY d.id</select><!--  部门列表查询id  --><select id="searchDeptById"  resultType="HashMap">select * from tb_dept where id = #{id}</select><!--  部门列表新增  --><insert id="insertDept">insert into tb_dept values(#{id},#{deptName},#{tel},#{email},#{desc})</insert><!--  部门列表更新  --><update id="updateDept">update tb_deptset `dept_name` = #{deptName},`tel`       = #{tel},`email`     = #{email},`desc`      = #{desc}where `id` = #{id}</update><!--  部门列表批量删除  --><delete id="deleteBatchDept">delete from tb_dept where id in<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach></delete>
</mapper>

4.3.3 Service 业务层

@Service
public class DeptService {@Resourceprivate DeptDao deptDao;//部门列表-查询全部public ArrayList<HashMap> searchAllDept() {ArrayList<HashMap> list = deptDao.searchAllDept();return list;}//部门列表-分页查询public PageInfo<HashMap> searchDept(Map param) {PageHelper.startPage(MapUtil.getInt(param,"pageNum"), MapUtil.getInt(param,"pageSize"));ArrayList<HashMap> list = deptDao.searchDept(param);PageInfo<HashMap> pageInfo = new PageInfo<>(list);return pageInfo;}//部门列表-查询idpublic HashMap searchDeptById(Integer id) {HashMap map = deptDao.searchDeptById(id);return map;}//部门列表-新增public int insertDept(Map param) {return deptDao.insertDept(param);}//部门列表-更新public int updateDept(Map param) {return deptDao.updateDept(param);}//部门列表-批量删除public int deleteBatchDept(Map param) {return deptDao.deleteBatchDept(param);}
}

4.3.4 Controller Web层

@RestController
@RequestMapping("/admin")
public class DeptController {@Resourceprivate DeptService deptService;/*** 部门管理-查询全部* @return*/@GetMapping("/dept/searchAllDept")@SaCheckPermission(value = {"SYSTEM:DEPT:SELECT"}, mode = SaMode.OR)public R searchAllDept() {ArrayList<HashMap> list = deptService.searchAllDept();return R.success(list);}/*** 部门管理-分页查询* @param deptSearchReq* @return*/@PostMapping("/dept/searchDeptByPage")@SaCheckPermission(value = {"SYSTEM:DEPT:SELECT"}, mode = SaMode.OR)public R searchDept(@Valid @RequestBody DeptSearchForm deptSearchReq) {Map param = BeanUtil.beanToMap(deptSearchReq);PageInfo<HashMap> list = deptService.searchDept(param);return R.success(list);}/*** 部门管理-查询id* @param id* @return*/@GetMapping("/dept/searchDeptById")@SaCheckPermission(value = {"SYSTEM:DEPT:SELECT"}, mode = SaMode.OR)public R searchDeptById(@RequestParam(value = "id") Integer id) {HashMap map = deptService.searchDeptById(id);if(ObjectUtil.isEmpty(map)) {return R.success("200","id不存在");}return R.success(map);}/*** 部门管理-编辑* @param deptEditReq* @return*/@PostMapping("/dept/editDept")@SaCheckPermission(value = {"SYSTEM:DEPT:EDIT"}, mode = SaMode.OR)public R insertDept(@Valid @RequestBody DeptEditForm deptEditReq) {Map param = BeanUtil.beanToMap(deptEditReq);if(ObjectUtil.isEmpty(deptEditReq.getId())) {deptService.insertDept(param);}else {deptService.updateDept(param);}return R.success();}/*** 部门管理-批量删除* @param deptDeleteReq* @return*/@PostMapping("/dept/deleteBatchDept")@SaCheckPermission(value = {"SYSTEM:DEPT:DELETE"}, mode = SaMode.OR)public R deleteBatchDept(@Valid @RequestBody DeptDeleteForm deptDeleteReq) {Map param = BeanUtil.beanToMap(deptDeleteReq);int rows = deptService.deleteBatchDept(param);return R.success(rows);}
}

4.3.5 部门页面编辑

在这里插入图片描述

4.4 权限管理实现

4.4.1 定义PermissionDao类实现接口

/**
* @author lenovo
* @description 针对表【tb_permission(权限表)】的数据库操作Mapper
* @createDate 2025-02-06 10:35:25
* @Entity com.example.his.api.db.pojo.PermissionEntity
*/
public interface PermissionDao {// 查询递归菜单权限public ArrayList<PermissionMenuResp> searchPermissions();// 权限管理-编辑public int insertPermission(Map param);public int updatePermission(Map param);// 权限管理-批量删除public int deleteBatchPermission(Map param);
}

4.4.2 配置PermissionDao.xml映射信息

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.his.api.db.dao.PermissionDao"><resultMap id="PermissionMenu" type="com.example.his.api.resp.PermissionMenuResp"><id property="id" column="id" jdbcType="INTEGER"/><result property="parentId" column="parent_id" jdbcType="INTEGER"/><result property="permissionName" column="permission_name" jdbcType="VARCHAR"/><result property="moduleName" column="module_name" jdbcType="VARCHAR"/><result property="menuType" column="menu_type" jdbcType="VARCHAR"/><result property="icon" column="icon" jdbcType="VARCHAR"/><result property="path" column="path" jdbcType="VARCHAR"/><result property="createTime" column="create_time" jdbcType="VARCHAR"/></resultMap><!--    <sql id="Base_Column_List">-->
<!--        id,parent_id,permission_name,-->
<!--        module_name,menu_type,icon,-->
<!--        path,create_time-->
<!--    </sql>--><!-- 查询用户现有权限 --><select id="searchPermissions" resultMap="PermissionMenu">select * from tb_permission order by sort asc</select><!-- 权限管理-新增 --><insert id="insertPermission">insert into tb_permission values(#{id},#{parentId},#{permissionName},#{moduleName},#{menuType},#{icon},#{path},#{createTime})</insert><!-- 权限管理-更新 --><update id="updatePermission">update tb_permissionset `parent_id`       = #{parentId},`permission_name` = #{permissionName},`module_name`     = #{moduleName},`menu_type`       = #{menuType},`icon`            = #{icon},`path`            = #{path},`create_time`     = #{createTime}where id = #{id}</update><!-- 权限管理-批量删除 --><delete id="deleteBatchPermission">delete from tb_permission where id in<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach></delete>
</mapper>

4.4.3 Service 业务层

@Service
public class PermissionService {@Resourceprivate PermissionDao permissionDao;// 权限管理-递归菜单public ArrayList<PermissionMenuResp> searchPermissions() {return deepTree(permissionDao.searchPermissions());}// 权限管理-编辑public int insertPermission(Map param) {return permissionDao.insertPermission(param);}public int updatePermission(Map param) {return permissionDao.updatePermission(param);}// 权限管理-批量删除public int deleteBatchPermission(Map param) {return permissionDao.deleteBatchPermission(param);}/*** 转换树形结构* @param menuList* @return*/public ArrayList<PermissionMenuResp> deepTree(ArrayList<PermissionMenuResp> menuList) {//创建list集合,用于数据最终封装ArrayList<PermissionMenuResp> finalNode = new ArrayList<>();for (PermissionMenuResp menus : menuList) {Integer topId = 0;//判断Pid是否等于0  0是最高的节点 将查询出的数据放进list集合if (topId.equals(menus.getParentId())) {finalNode.add(selectTree(menus, menuList));}}// 递归设置节点层级for (PermissionMenuResp menu : finalNode) {setNodeLevel(menu,1);}return finalNode;}public PermissionMenuResp selectTree(PermissionMenuResp m1, ArrayList<PermissionMenuResp> menuList) {//因为向一层菜单里面放二层菜单,二层里面还要放三层,把对象初始化m1.setChildren(new ArrayList<PermissionMenuResp>());//遍历所有菜单list集合,进行判断比较,比较id和pid值是否相同for (PermissionMenuResp m2 : menuList) {//判断 id和pid值是否相同if (m1.getId().equals(m2.getParentId())) {//如果children为空,进行初始化操作if (m1.getChildren() == null) {m1.setChildren(new ArrayList<PermissionMenuResp>());}//把查询出来的子菜单放到父菜单里面m1.getChildren().add(selectTree(m2, menuList));}}return m1;}// 递归设置节点层级public void setNodeLevel(PermissionMenuResp node, int level) {node.setLevel(level);node.setKey(node.getId());for (PermissionMenuResp child : node.getChildren()) {setNodeLevel(child, level + 1);}}
}

4.4.4 Controller Web层

@RestController
@RequestMapping("/admin")
public class PermissionController {@Resourceprivate PermissionService permissionService;/*** 权限管理-递归菜单* @return*/@GetMapping("/permissions/searchPermissions")@SaCheckPermission(value = {"SYSTEM:PERMISSION:SELECT"}, mode = SaMode.OR)public R searchPermissions() {ArrayList<PermissionMenuResp> permissions = permissionService.searchPermissions();return  R.success(permissions);}/*** 权限管理-编辑* @param permissionEditReq* @return*/@PostMapping("/permissions/editPermissions")@SaCheckPermission(value = {"SYSTEM:PERMISSION:EDIT"}, mode = SaMode.OR)public R editPermissions(@Valid @RequestBody PermissionEditReq permissionEditReq) {Map param = BeanUtil.beanToMap(permissionEditReq);if(ObjectUtil.isEmpty(permissionEditReq.getId())) {permissionService.insertPermission(param);}else {permissionService.updatePermission(param);}return  R.success();}/*** 权限管理-批量删除* @param permissionDeleteReq* @return*/@PostMapping("/permissions/deleteBatchPermission")@SaCheckPermission(value = {"SYSTEM:PERMISSION:DELETE"}, mode = SaMode.OR)public R deleteBatchPermission(@Valid @RequestBody PermissionDeleteReq permissionDeleteReq) {Map param = BeanUtil.beanToMap(permissionDeleteReq);Integer rows = permissionService.deleteBatchPermission(param);return R.success(rows);}
}

4.4.5 权限列表编辑

在这里插入图片描述

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

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

相关文章

工商业储能的“智慧大脑”:解密 Acrel-2000ES EMS 的核心功能与价值

安科瑞电气顾强 市场背景&#xff1a;工商业储能加速崛起 2022年中国已并网的储能项目中&#xff0c;用户侧并网占比为8.36%&#xff0c;其中工商业储能占据了用户侧高达98.6%的份额。驱动这一市场发展的关键因素日益显著&#xff1a; 1.峰谷价差扩大&#xff1a; 全国各省市…

vue+threeJs 根据屏幕调整gltf模型的大小、重心、并更换骑车整体颜色

嗨&#xff0c;我是小路。今天主要和大家分享的主题是“vuethreeJs 根据屏幕调整gltf模型的大小、重心、并更换骑车整体颜色”。 项目案例示意图 1.整体更换gltf模型的颜色 定义&#xff1a;整体代码如下。颜色是事先设定的 const colorAry reactive(["rgb(21…

03 基于 java udp 做一个dns服务器 和 一个dns代理服务器

前言 这个也是 来自于一个朋友的需求 最终的目的是实现一个 dns 代理服务器, 当然 这本质也是一个 dns 服务器 并且 dns 代理服务器是依赖于 一个 dns 服务器的, 因此 顺便给一个 dns 服务器的 demo 这里 主要是 基于 udp 的一个 dns 请求, 响应数据的交互 dns 服务器 …

【HITCSAPP 哈工大计算机系统期末大作业】 程序人生-Hello’s P2P

计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 计算机与电子通信类 学   号 2023112915 班   级 23L0505 学 生 杨昕彦 指 导 教 师 刘宏伟 计算机科学…

第十周作业

一、CSRF 1、DVWA-High等级 2、使用Burp生成CSRF利用POC并实现攻击 二、SSRF&#xff1a;file_get_content实验&#xff0c;要求获取ssrf.php的源码 三、RCE 1、 ThinkPHP 2、 Weblogic 3、Shiro

PTA刷题笔记(难度预警!!!有详解)

7-18 二分法求多项式单根 代码如下&#xff1a; ​ #include <stdio.h> #include <math.h>// 定义多项式函数 double polynomial(double x, double a3, double a2, double a1, double a0) {return a3 * x * x * x a2 * x * x a1 * x a0; }// 二分法求根函数 do…

打破传统范式,线上 3D 画展彰显多元亮点

&#xff08;一&#xff09;沉浸式体验&#xff0c;身临其境赏画​ 线上 3D 画展运用先进的 3D 建模和虚拟现实&#xff08;VR&#xff09;技术&#xff0c;高度还原了真实的展厅环境 。展厅内的布局、灯光&#xff0c;甚至墙壁的质感都被完美复刻&#xff0c;让观众仿佛置身于…

Docker架构详解

一,Docker的四大要素&#xff1a;Dockerfile、镜像(image)、容器(container)、仓库(repository) 1.dockerfile&#xff1a;在dockerfile文件中写构建docker的命令,通过dockerbuild构建image 2.镜像&#xff1a;就是一个只读的模板&#xff0c;镜像可以用来创建docker容器&…

【工具类】常用的工具类——CollectionUtil

目录 cn.hutool.core.collection.CollectionUtil集合创建集合清空集合判空集合去重集合过滤集合转换集合合并集合交集集合差集集合是否包含元素集合是否包含指定元素&#xff08;自定义条件&#xff09;集合分页集合分组集合转字符串元素添加元素删除根据属性转Map获取元素获取…

从零起步搭建基于华为云构建碳排放设备管理系统的产品设计

目录 &#x1f33f; 华为云 IoT&#xff1a;轻松上手碳排放设备管理系统搭建 &#x1f30d; 逐步搭建搭建规划 &#x1f680; 一、系统蓝图&#xff1a;5大核心模块&#xff0c;循序渐进 1️⃣ 设备管理与数据采集层 2️⃣ 数据传输与协议转换层 3️⃣ 数据处理与分析层…

华为OD机试真题—— 小明减肥(2025B卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 B卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

数据结构 -- 插入排序(直接插入排序和希尔排序)

插入排序 算法思想 每次将⼀个待排序的记录按其关键字大小插入到前面已排好序的子序列中&#xff0c;直到全部记录插入完成。 代码实现 void InsertSort(int A[],int n){int i,j,temp;for(i 1;i<n;i){if(A[i]<A[i-1]){temp A[i]; //用temp暂存A[i]for(ji-1;j>…

word中表格拉不动以及插入图片有间距

word中的表格宽度和高度怎么调整都改不了&#xff0c;可以将选中表格—右键—段落—取消勾选下图中的两项。 word中表格插入图片始终有间隙&#xff0c;怎么也消除不了间隙&#xff0c;可以在表布局—单元格边距—修改上下左右边距为0即可

网络抓包命令tcpdump及分析工具wireshark使用

文章目录 环境文档用途详细信息 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 8,Linux x86-64 Red Hat Enterprise Linux 7,Linux x86-64 SLES 12,银河麒麟 &#xff08;鲲鹏&#xff09;,银河麒麟 &#xff08;X86_64&#xff09;,银河麒麟&#xff08;龙…

Eigen矩阵存储顺序以及转换

一、Eigen矩阵存储顺序 在矩阵运算和线性代数中,"行优先"(Row-major)和"列优先"(Column-major)是两种不同的存储方式,它们决定了多维数组(如矩阵)在内存中的布局顺序。 1. 行优先(Row-major) 定义:矩阵按行顺序存储在内存中,即第一行的所有元…

快速部起一个Openwhisk平台,使用telego k8s服务部署能力内网部署

Telego 简介与 OpenWhisk 部署实践 概述 Telego 是一个用于便携式 Kubernetes 部署的工具&#xff0c;旨在解决容器镜像拉取中的网络代理问题。本文档描述了如何通过 Telego 将 Apache OpenWhisk&#xff08;一个 Serverless 计算平台&#xff09;部署到 Kubernetes 集群&…

LockSupport与Condition解析

本章我们介绍两个Java 并发包中用于线程协作的工具--LockSupport和Condition LockSupport&#xff1a; Java 并发包&#xff08;java.util.concurrent.locks&#xff09;提供了基于许可&#xff08;permit&#xff09;的线程阻塞和唤醒机制--LockSupport 对于LockSupport是通…

【机器学习基础】机器学习入门核心算法:逻辑回归(Decision Tree)

机器学习入门核心算法&#xff1a;逻辑回归&#xff08;Decision Tree&#xff09; 一、算法逻辑1.1 基本概念1.2 算法流程 二、算法原理与数学推导2.1 特征选择指标信息熵&#xff08;ID3算法&#xff09;信息增益&#xff08;Information Gain&#xff09;信息增益率&#xf…

网络编程3

管道的性质 读缓冲区为空&#xff0c;read阻塞写缓冲区为空&#xff0c;write阻塞一端先close&#xff0c;另一端继续read&#xff0c;read不阻塞&#xff0c;立刻返回0一端先close&#xff0c;另一端继续write&#xff0c;write会触发SIGPIPE信号&#xff0c;进程异常终止 soc…

influxdb时序数据库

以下概念及操作均来自influxdb2 官方文档 InfluxDB2 is the platform purpose-built to collect, store, process and visualize time series data. Time series data is a sequence of data points indexed in time order. Data points typically consist of successive meas…