实战开发——大部分公司都在用的角色权限控制

介绍

代码部分为自己手写,逻辑简单,具体逻辑还需根据公司具体业务,整体思路逻辑是大部分公司通用的。

建库

角色权限控制,基本开发都是下面三张表,可以直接拷贝。

  • menu 权限表
CREATE TABLE `menu` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `menu_name` varchar(128) DEFAULT NULL COMMENT '菜单名称',
  `level` tinyint(4) DEFAULT NULL COMMENT '菜单级别',
  `pid` int(11) DEFAULT NULL COMMENT '父菜单ID',
  `create_id` int(11) DEFAULT NULL COMMENT '创建人ID',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_id` int(11) DEFAULT NULL COMMENT '修改人',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `state` tinyint(4) DEFAULT NULL COMMENT '删除标记 0 未删除 1 已删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  • user_role 角色表
CREATE TABLE `user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '角色名称',
  `create_id` int(11) DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_id` int(11) DEFAULT NULL COMMENT '修改人',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `state` tinyint(4) DEFAULT NULL COMMENT '删除标记 0 未删除 1 已删除',
  PRIMARY KEY (`Id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
  • menu_role_ref 角色权限中间表
CREATE TABLE `menu_role_ref` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `menu_id` int(11) DEFAULT NULL COMMENT '菜单ID',
  `user_role_id` int(11) DEFAULT NULL COMMENT '用户角色ID',
  `create_id` int(11) DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_id` int(11) DEFAULT NULL COMMENT '修改人',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

接口部分

为了方便理解,我会写出完整逻辑过程,从controller -> service -> mapper

1. 权限列表树形菜单

controller:

    /**
     * 权限列表树形菜单
     *
     * @return
     */
    @GetMapping("/permission/list")
    public ResultEntity menuList() {
        return menuService.menuList();
    }

service:

    @Override
    public ResultEntity menuList() {
        ResultEntity result = new ResultEntity();
        List<Menu> menus = menuMapper.selectAll();
        if (CollectionUtils.isEmpty(menus)) {
            result.setCode(4000);
            result.setMsg("数据库数据为空");
            return result;
        }
        Map<Integer, List<Menu>> pidMap = menus.stream().collect(Collectors.groupingBy(Menu::getPid));
        Menu menu = new Menu();
        // 递归调用填充数据
        addMenuByPid(menu, pidMap);
        result.setCode(200);
        result.setMsg("查询成功");
        result.setData(menu.getChildren());
        return result;
    }

    /**
     * 将菜单分级嵌套组合
     *
     */
    private void addMenuByPid(Menu menu, Map<Integer, List<Menu>> pidMap) {
        if (Objects.isNull(menu.getId())) { // 一级菜单
            menu.setChildren(pidMap.get(0));
        } else {
            // 获取当前菜单的子菜单
            List<Menu> childMenu = pidMap.get(menu.getId());
            // 将子菜单插入当前菜单
            menu.setChildren(childMenu);
        }
        if (!CollectionUtils.isEmpty(menu.getChildren())) { // 子菜单为空时跳出递归
            // 当前菜单下填充子菜单
            menu.getChildren().forEach(m -> addMenuByPid(m, pidMap));
        }
    }

mapper:

    <select id="selectAll" resultType="com.zlp.demo.entity.Menu">
        SELECT id, menu_name, level, pid, create_id, create_time, update_id, update_time, state
        FROM menu
        WHERE state = 0
    </select>

接口返回结果:

{
    "code": 200,
    "msg": "查询成功",
    "data": [
        {
            "id": 1,
            "menuName": "一级菜单1",
            "level": 1,
            "pid": 0,
            "state": 0,
            "createId": 0,
            "createTime": "2021-12-28T03:03:56.000+00:00",
            "updateId": 0,
            "updateTime": "2021-12-28T03:04:01.000+00:00",
            "children": [
                {
                    "id": 3,
                    "menuName": "二级菜单11",
                    "level": 2,
                    "pid": 1,
                    "state": 0,
                    "createId": 0,
                    "createTime": "2021-12-28T03:05:05.000+00:00",
                    "updateId": 0,
                    "updateTime": "2021-12-28T03:05:09.000+00:00",
                    "children": [
                        {
                            "id": 7,
                            "menuName": "三级菜单31",
                            "level": 3,
                            "pid": 3,
                            "state": 0,
                            "createId": 0,
                            "createTime": "2021-12-28T03:07:01.000+00:00",
                            "updateId": 0,
                            "updateTime": "2021-12-28T03:07:10.000+00:00",
                            "children": null
                        },
                        {
                            "id": 8,
                            "menuName": "三级菜单32",
                            "level": 3,
                            "pid": 3,
                            "state": 0,
                            "createId": 0,
                            "createTime": "2021-12-28T08:00:56.000+00:00",
                            "updateId": 0,
                            "updateTime": "2021-12-28T08:00:56.000+00:00",
                            "children": null
                        }
                    ]
                },
                {
                    "id": 4,
                    "menuName": "二级菜单12",
                    "level": 2,
                    "pid": 1,
                    "state": 0,
                    "createId": 0,
                    "createTime": "2021-12-28T03:05:34.000+00:00",
                    "updateId": 0,
                    "updateTime": "2021-12-28T03:05:38.000+00:00",
                    "children": null
                }
            ]
        },
        {
            "id": 2,
            "menuName": "一级菜单2",
            "level": 1,
            "pid": 0,
            "state": 0,
            "createId": 0,
            "createTime": "2021-12-28T03:04:26.000+00:00",
            "updateId": 0,
            "updateTime": "2021-12-28T03:04:30.000+00:00",
            "children": [
                {
                    "id": 5,
                    "menuName": "二级菜单21",
                    "level": 2,
                    "pid": 2,
                    "state": 0,
                    "createId": 0,
                    "createTime": "2021-12-28T03:06:00.000+00:00",
                    "updateId": 0,
                    "updateTime": "2021-12-28T03:06:04.000+00:00",
                    "children": null
                },
                {
                    "id": 6,
                    "menuName": "二级菜单22",
                    "level": 2,
                    "pid": 2,
                    "state": 0,
                    "createId": 0,
                    "createTime": "2021-12-28T03:06:33.000+00:00",
                    "updateId": 0,
                    "updateTime": "2021-12-28T03:06:35.000+00:00",
                    "children": null
                }
            ]
        }
    ]
}

2. 添加权限

@Data
public class MenuRequest {
    // 权限名称
    private String menuName;
    // 权限层级
    private Integer level;
    // 权限父id
    private Integer pid;


}

controller:

    /**
     * 添加权限
     *
     * @param request
     * @return
     */
    @PostMapping("/permission/add")
    public ResultEntity menuAdd(@RequestBody MenuRequest request) {
        return menuService.menuAdd(request);
    }

service:

    @Override
    public ResultEntity menuAdd(MenuRequest request) {
        Menu menu = new Menu();
        menu.setMenuName(request.getMenuName());
        menu.setLevel(request.getLevel());
        menu.setPid(request.getPid());
        menu.setCreateId(0); // 根据具体业务逻辑获取当前登陆人id
        menu.setCreateTime(new Date());
        menu.setUpdateId(0);
        menu.setUpdateTime(new Date());
        menu.setState(0);
        menuMapper.insertMenu(menu);
        return new ResultEntity();
    }

mapper:

    <insert id="insertMenu">
        insert menu(menu_name, level, pid, create_id, create_time, update_id, update_time, state)
        values(
            #{menuName,jdbcType=VARCHAR},#{level,jdbcType=INTEGER},#{pid,jdbcType=INTEGER},
            #{createId,jdbcType=INTEGER},#{createTime,jdbcType=TIMESTAMP},#{updateId,jdbcType=INTEGER},
            #{updateTime,jdbcType=TIMESTAMP},#{state,jdbcType=INTEGER}
        )
    </insert>

3. 删除权限
这里根据具体业务逻辑,需要注意删除某个权限时是否考虑删除该权限下的子权限。这里暂时不考虑,不影响使用。
controller:

    /**
     * 删除权限
     * 
     * @param request
     * @return
     */
    @PostMapping("/permission/delete")
    public ResultEntity menuDelete(@RequestBody MenuRequest request) {
        return menuService.menuDelete(request);
    }

service:

    @Override
    public ResultEntity menuDelete(MenuRequest request) {
        ResultEntity result = new ResultEntity();
        Integer id = request.getId();// 权限主键
        if (Objects.isNull(id)) {
            result.setCode(4001);
            result.setMsg("参数为空");
            return result;
        }
        menuMapper.updateState(id);
        result.setCode(200);
        result.setMsg("删除成功");
        return result;
    }

mapper:

    <update id="updateState">
        update menu
        set state = 1
        where id = #{id,jdbcType=INTEGER}
    </update>

演示:这里删除 二级菜单11 id是 3
在这里插入图片描述
再次查询list结果:可以看到一级菜单1 下面的子菜单 二级菜单11 没有了,二级菜单11 下面的三级菜单也没有了(ps:这里三级菜单在数据库中的state状态还是可用的)

{
    "code": 200,
    "msg": "查询成功",
    "data": [
        {
            "id": 1,
            "menuName": "一级菜单1",
            "level": 1,
            "pid": 0,
            "state": 0,
            "createId": 0,
            "createTime": "2021-12-28T03:03:56.000+00:00",
            "updateId": 0,
            "updateTime": "2021-12-28T03:04:01.000+00:00",
            "children": [
                {
                    "id": 4,
                    "menuName": "二级菜单12",
                    "level": 2,
                    "pid": 1,
                    "state": 0,
                    "createId": 0,
                    "createTime": "2021-12-28T03:05:34.000+00:00",
                    "updateId": 0,
                    "updateTime": "2021-12-28T03:05:38.000+00:00",
                    "children": null
                }
            ]
        },
        {
            "id": 2,
            "menuName": "一级菜单2",
            "level": 1,
            "pid": 0,
            "state": 0,
            "createId": 0,
            "createTime": "2021-12-28T03:04:26.000+00:00",
            "updateId": 0,
            "updateTime": "2021-12-28T03:04:30.000+00:00",
            "children": [
                {
                    "id": 5,
                    "menuName": "二级菜单21",
                    "level": 2,
                    "pid": 2,
                    "state": 0,
                    "createId": 0,
                    "createTime": "2021-12-28T03:06:00.000+00:00",
                    "updateId": 0,
                    "updateTime": "2021-12-28T03:06:04.000+00:00",
                    "children": null
                },
                {
                    "id": 6,
                    "menuName": "二级菜单22",
                    "level": 2,
                    "pid": 2,
                    "state": 0,
                    "createId": 0,
                    "createTime": "2021-12-28T03:06:33.000+00:00",
                    "updateId": 0,
                    "updateTime": "2021-12-28T03:06:35.000+00:00",
                    "children": null
                }
            ]
        }
    ]
}

4. 角色列表

controller:

    /**
     * 角色列表
     *
     * @return
     */
    @GetMapping("/role/list")
    public ResultEntity roleList() {
        return menuService.roleList();
    }

service:

    @Override
    public ResultEntity roleList() {
        ResultEntity result = new ResultEntity();
        List<Role> roles = menuMapper.selectRoleAll();
        result.setCode(200);
        result.setMsg("查询成功");
        result.setData(roles);
        return result;
    }

mapper:

    <select id="selectRoleAll" resultType="com.zlp.demo.entity.Role">
        select id,role_name,create_id,create_time,update_id,update_time,state
        from user_role
        where state = 0
    </select>

测试结果:

{
    "code": 200,
    "msg": "查询成功",
    "data": [
        {
            "id": 1,
            "roleName": "超管",
            "createId": 0,
            "createTime": "2021-12-31T02:36:33.000+00:00",
            "updateId": 0,
            "updateTime": "2021-12-31T02:36:36.000+00:00",
            "state": 0
        },
        {
            "id": 2,
            "roleName": "经理",
            "createId": 0,
            "createTime": "2021-12-31T02:36:53.000+00:00",
            "updateId": 0,
            "updateTime": "2021-12-31T02:36:59.000+00:00",
            "state": 0
        }
    ]
}

5. 添加角色

controller:

    /**
     * 创建角色
     *
     * @param request
     * @return
     */
    @PostMapping("/role/add")
    public ResultEntity roleAdd(@RequestBody MenuRequest request) {
        return menuService.roleAdd(request);
    }

service:

    @Override
    public ResultEntity roleAdd(MenuRequest request) {
        ResultEntity result = new ResultEntity();
        Role role = new Role();
        role.setRoleName(request.getRoleName());
        role.setCreateId(0);
        role.setCreateTime(new Date());
        role.setUpdateId(0);
        role.setUpdateTime(new Date());
        role.setState(0);
        menuMapper.createRole(role);
        return result;
    }

mapper:

    <insert id="createRole">
        insert into user_role(role_name,create_id,create_time,update_id,update_time,state)
        values(#{roleName,jdbcType=VARCHAR},#{createId,jdbcType=INTEGER},
      #{createTime,jdbcType=TIMESTAMP},
               #{updateId,jdbcType=INTEGER},#{updateTime,jdbcType=TIMESTAMP},
      #{state,jdbcType=INTEGER}
              )
    </insert>

6. 删除角色

controller:

    /**
     * 删除角色
     *
     * @param request
     * @return
     */
    @PostMapping("/role/delete")
    public ResultEntity roleDelete(@RequestBody MenuRequest request) {
        return menuService.roleDelete(request);
    }

service:

    @Override
    public ResultEntity roleDelete(MenuRequest request) {
        Integer id = request.getId();
        menuMapper.updateRoleById(id);
        return new ResultEntity();
    }

mapper:

    <update id="updateRoleById">
        update user_role
        set state = 1
        where id = #{id,jdbcType=INTEGER}
    </update>

7. 为角色添加权限

参数传递:

{
    "menuIds": [1,3,8], // 权限id集合
    "roleId": 3 // 角色id
}
    // 权限ids
    private List<Integer> menuIds;
    // 角色id
    private Integer roleId;

controller:

    /**
     * 为角色分配权限
     *
     * @param request
     * @return
     */
    @PostMapping("/add/role/permission")
    public ResultEntity addRolePermission(@RequestBody MenuRequest request) {
        return menuService.addRolePermission(request);
    }

service:

    @Override
    public ResultEntity addRolePermission(MenuRequest request) {
        List<Integer> menuIds = request.getMenuIds();
        Integer roleId = request.getRoleId();
        List<MenuRole> menuRoles = new ArrayList<>();
        if (Objects.isNull(menuIds)) return new ResultEntity();
        for (Integer menuId : menuIds) {
            MenuRole menuRole = new MenuRole();
            menuRole.setMenuId(menuId);
            menuRole.setUserRoleId(roleId);
            menuRole.setCreateId(0);
            menuRole.setCreateTime(new Date());
            menuRole.setUpdateId(0);
            menuRole.setUpdateTime(new Date());
            menuRoles.add(menuRole);
        }
        // 删除之前的角色权限
        menuMapper.deleteMenuRoleByRoleId(menuIds);
        // 添加新的角色权限
        menuMapper.addMenuRole(menuRoles);
        return new ResultEntity();
    }

mapper:

    <delete id="deleteMenuRoleByRoleId">
        delete from menu_role_ref
        where user_role_id in
        <foreach collection="menuIds" item="item" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </delete>

    <insert id="addMenuRole">
        insert into menu_role_ref(menu_id,user_role_id,create_id,create_time,update_id,update_time)
        values
        <foreach collection="menuRoles" item="item" separator=",">
            (#{item.menuId,jdbcType=INTEGER},#{item.userRoleId,jdbcType=INTEGER},
          	 #{item.createId,jdbcType=INTEGER},#{item.createTime,jdbcType=TIMESTAMP},
          	 #{item.updateId,jdbcType=INTEGER},#{item.updateTime,jdbcType=TIMESTAMP}
            )
        </foreach>
    </insert>

8. 用户添加角色
实际业务中user表中是有用户角色这个字段的,当然也可以单独创建一个中间表来存用户角色关系,这里就按user表中是存在角色字段的(ps:我们之前公司业务也是这样的)

参数:

{
    "id": 1, // 用户id
    "roleId": 3 // 角色id
}

controller:

    /**
     * 用户添加角色
     *
     * @param request
     * @return
     */
    @PostMapping("/add/user/role")
    public ResultEntity addUserRole(@RequestBody MenuRequest request) {
        return menuService.addUserRole(request);
    }

service:

    @Override
    public ResultEntity addUserRole(MenuRequest request) {
        ResultEntity resultEntity = new ResultEntity();
        Integer roleId = request.getRoleId();
        Integer userId = request.getId();
        // 查询当前用户
        User user = menuMapper.selectUserByid(userId);
        if (Objects.isNull(user)) {
            resultEntity.setCode(4000);
            resultEntity.setMsg("未查到该用户");
            return resultEntity;
        }
        // 更新当前用户角色
        menuMapper.updateUserRole(roleId, userId);
        resultEntity.setCode(200);
        resultEntity.setMsg("成功");
        return resultEntity;
    }

mapper:

    <update id="updateUserRole">
        update user
        set role_id = #{roleId,jdbcType=INTEGER}
        where id = #{userId,jdbcType=INTEGER}
    </update>

9. 查看用户拥有权限

重点,前面这些都是为实现这个接口的铺垫

参数:

{
    "roleId": 3 // 当前用户的角色id
}

controller:

    /**
     * 查询用户权限
     *
     * @param request
     * @return
     */
    @PostMapping("/query/user/permission")
    public ResultEntity queryPermission(@RequestBody MenuRequest request) {
        return menuService.queryPermission(request);
    }

service:

    @Override
    public ResultEntity queryPermission(MenuRequest request) {
        ResultEntity resultEntity = new ResultEntity();
        Integer roleId = request.getRoleId();
        // 查询角色拥有的权限
        List<MenuRole> menuRoles = menuMapper.selectMenuRoleByRoleId(roleId);
        if (Objects.isNull(menuRoles)) {
            resultEntity.setCode(4000);
            resultEntity.setMsg("该角色暂没添加权限");
            return resultEntity;
        }
        List<Integer> menuIds = menuRoles.stream().map(MenuRole::getMenuId).collect(Collectors.toList());
        // 查询权限信息
        List<Menu> menus = menuMapper.selectMenuByIds(menuIds);
        Map<Integer, List<Menu>> pidMap = menus.stream().collect(Collectors.groupingBy(Menu::getPid));
        Menu menu = new Menu();
        // 递归调用填充数据
        addMenuByPid(menu, pidMap);
        resultEntity.setMsg("success");
        resultEntity.setCode(200);
        resultEntity.setData(menu.getChildren());
        return resultEntity;
    }

    /**
     * 将菜单分级嵌套组合
     *
     */
    private void addMenuByPid(Menu menu, Map<Integer, List<Menu>> pidMap) {
        if (Objects.isNull(menu.getId())) { // 一级菜单
            menu.setChildren(pidMap.get(0));
        } else {
            // 获取当前菜单的子菜单
            List<Menu> childMenu = pidMap.get(menu.getId());
            // 将子菜单插入当前菜单
            menu.setChildren(childMenu);
        }
        if (!CollectionUtils.isEmpty(menu.getChildren())) { // 子菜单为空时跳出递归
            // 当前菜单下填充子菜单
            menu.getChildren().forEach(m -> addMenuByPid(m, pidMap));
        }
    }

mapper:

    <select id="selectMenuRoleByRoleId" resultType="com.zlp.demo.entity.MenuRole">
        select menu_id,user_role_id,create_id,create_time,update_id,update_time
        from menu_role_ref
        where user_role_id = #{roleId,jdbcType=INTEGER}
    </select>

    <select id="selectMenuByIds" resultType="com.zlp.demo.entity.Menu">
        select id, menu_name, level, pid, create_id, create_time, update_id, update_time, state
        from menu
        where id in
        <foreach collection="menuIds" item="item" separator="," open="(" close=")">
            #{item}
        </foreach>
        and state = 0
    </select>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1个凡夫俗子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值