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

发布于:2025-05-29 ⋅ 阅读:(22) ⋅ 点赞:(0)

Java系列文章



前言

本文将介绍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 {
    @Resource
    private UserDao userDao;

    /**
     * 返回一个用户所拥有的权限集合
     */
    @Override
    public 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;
    }


    /**
     * 返回一个用户所拥有的角色标识集合
     */
    @Override
    public 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 mapper
        PUBLIC "-//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_name
        FROM tb_user u
                 JOIN 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.icon
        FROM tb_user u
                 JOIN 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 id
        from tb_user
        where 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_role
        WHERE JSON_CONTAINS ( u.role, CONVERT (id, CHAR) )
        ) AS roles
        FROM tb_user u
        JOIN 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_user
        SET
        username=#{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_user
        SET
        name=#{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 {
    @Resource
    private UserDao userMapper;

    // 用户管理-查询id
    public 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 {

    @Resource
    private UserService userService;

    @Resource
    private 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传递userId
            StpUtil.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 mapper
        PUBLIC "-//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">
        SELECT
        r.id,
        r.role_name AS roleName,
        COUNT( u.id ) AS users,
        JSON_LENGTH ( r.permissions ) AS permissionsLength,
        r.permissions,
        r.desc,
        r.systemic,
        r.echo
        FROM tb_role r
        LEFT 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.id
        ORDER BY r.id
    </select>
    <!-- 角色管理-新增 -->
    <insert id="insertRole">
        insert into tb_role
        SET
        role_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 {

    @Resource
    private 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 {

    @Resource
    private 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 mapper
        PUBLIC "-//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">
        select
        d.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 = 1
                AND 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_dept
        set `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 {

    @Resource
    private 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;
    }

    //部门列表-查询id
    public 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 {
    @Resource
    private 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 mapper
        PUBLIC "-//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_permission
        set `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 {

    @Resource
    private 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 {

    @Resource
    private 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 权限列表编辑

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到