项目日记(在线办公项目)day2021/02/26

博客围绕权限菜单的动态生成展开,介绍了根据当前登录者权限显示菜单以实现权限控制。阐述了数据库中与权限菜单生成相关的表,如账户表、角色表等及其关系。还说明了数据格式处理、通过用户名查权限的SQL语句,完成后端数据模型构建后编写前端并测试成功。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、权限菜单的动态生成

权限菜单应该根据当前登录者所拥有的权限显示菜单,以到达权限控制的目录

权限菜单中显示的菜单为当前用户所拥有的权限

权限菜单是根据数据库生成,数据库中有关权限菜单生成的有以下几张表:

  • 账户表(用户表):描述系统账户信息

  • 账户角色表:描述系统中不同账户所拥有的角色

    一个账户可以有多个角色,一个角色可以分配给不同的账户。

    账户表和角色表是多对多的关系。

  • 角色表:描述系统中角色信息(权限组)

  • 角色权限表:描述一个角色所拥有的权限

    一个角色可以有多个权限,一个权限可以分配不同的角色。

    角色表和权限表是多对多的关系。

我们需要的数据格式是这样的:

在这里插入图片描述

我们的数据库中,模块表的形式是纵向的,现在的这种数据表示的形式是纵向的,最好的方式是模块表进行一次自连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tp6xHGTm-1614334951049)(项目日记.assets/在这里插入图片描述
)]

并且如果要生成菜单,我们在数据库中给它的表示形式是"module_is_menu"为1。

在上一次,我们将当前用户的信息封装到了session中,所以我们不妨通过用户名来查找该用户所拥有的权限,这涉及到以下几个表:

tbl_module 与 tbl_role_module :通过module_id进行关联
tbl_role_module 与 tbl_role :通过role_id进行关联
tbl_account_role 与tbl_role :通过role_id进行关联

通过账户姓名来查询其菜单的sql语句如下:

SELECT
            DISTINCT
            p.module_id AS p_id,
            p.module_name AS p_name,
            s.module_id AS s_id,
            s.module_name AS s_name,
            s.module_url AS s_url
        FROM
            tbl_module p
                INNER JOIN tbl_module s
                           ON p.module_id=s.parent_module_id
                INNER JOIN tbl_role_module rm
                           ON s.module_id=rm.module_id
                INNER JOIN tbl_role r
                           ON rm.role_id=r.role_id
                INNER JOIN tbl_account_role ar
                           ON r.role_id = ar.role_id
                INNER JOIN tbl_account a
                           ON ar.account_id=a.account_id
        WHERE
                p.module_is_menu=1 AND
                s.module_is_menu=1 AND
                a.account_name=#{account_name}

查询admin用户的菜单数据,返回的表为:

在这里插入图片描述

现在我们根据这个表,构建一个这个表对应的实体类:

package com.jiazhong.office.model;

/**
 * @ClassName: Module
 * @Description: TODO 模块实体类,根据sql查询语句建立的实体类
 * @Author: JiaShiXi
 * @Date: 2021/2/26 12:51
 * @Version: 1.0
 **/

public class Module {
    private Integer p_id; //父模块编号
    private String p_name; //父模块名称
    private Integer s_id; //子模块编号
    private String s_name; //子模块名称
    private String s_url; //子模块url

    public Integer getP_id() {
        return p_id;
    }

    public void setP_id(Integer p_id) {
        this.p_id = p_id;
    }

    public String getP_name() {
        return p_name;
    }

    public void setP_name(String p_name) {
        this.p_name = p_name;
    }

    public Integer getS_id() {
        return s_id;
    }

    public void setS_id(Integer s_id) {
        this.s_id = s_id;
    }

    public String getS_name() {
        return s_name;
    }

    public void setS_name(String s_name) {
        this.s_name = s_name;
    }

    public String getS_url() {
        return s_url;
    }

    public void setS_url(String s_url) {
        this.s_url = s_url;
    }

    @Override
    public String toString() {
        return "Module{" +
                "p_id=" + p_id +
                ", p_name='" + p_name + '\'' +
                ", s_id=" + s_id +
                ", s_name='" + s_name + '\'' +
                ", s_url='" + s_url + '\'' +
                '}';
    }
}

接下来,编写Dao层数据:

package com.jiazhong.office.dao.rbac;

import com.jiazhong.office.model.Module;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @InterfaceName: MainMenuDao
 * @Description: TODO 主菜单生成Dao
 * @Author: JiaShiXi
 * @Date: 2021/2/26 12:49
 * @Version: 1.0
 **/

@Repository
public interface ModuleDao {

    /**
     * 通过账户名查询模块集合
     * @return
     */
    public List<Module> getModuleListByAccountName(@Param("account_name") String account_name);
}

<?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.jiazhong.office.dao.rbac.ModuleDao">

    <select id="getModuleListByAccountName" resultType="com.jiazhong.office.model.Module">
        SELECT
            DISTINCT
            p.module_id AS p_id,
            p.module_name AS p_name,
            s.module_id AS s_id,
            s.module_name AS s_name,
            s.module_url AS s_url
        FROM
            tbl_module p
                INNER JOIN tbl_module s
                           ON p.module_id=s.parent_module_id
                INNER JOIN tbl_role_module rm
                           ON s.module_id=rm.module_id
                INNER JOIN tbl_role r
                           ON rm.role_id=r.role_id
                INNER JOIN tbl_account_role ar
                           ON r.role_id = ar.role_id
                INNER JOIN tbl_account a
                           ON ar.account_id=a.account_id
        WHERE
                p.module_is_menu=1 AND
                s.module_is_menu=1 AND
                a.account_name=#{account_name}
    </select>

</mapper>

编写菜单视图模型:

package com.jiazhong.office.model.view;

import java.util.List;

/**
 * @ClassName: MenuView
 * @Description: TODO 菜单视图实体类
 * @Author: JiaShiXi
 * @Date: 2021/2/26 12:42
 * @Version: 1.0
 **/

public class MenuView {
    private Integer menuId; //菜单编号
    private String menuName; //菜单名称
    private String menuUrl; //菜单路径
    private List<MenuView> subMenuList; //子菜单项

    public Integer getMenuId() {
        return menuId;
    }

    public void setMenuId(Integer menuId) {
        this.menuId = menuId;
    }

    public String getMenuName() {
        return menuName;
    }

    public void setMenuName(String menuName) {
        this.menuName = menuName;
    }

    public String getMenuUrl() {
        return menuUrl;
    }

    public void setMenuUrl(String menuUrl) {
        this.menuUrl = menuUrl;
    }

    public List<MenuView> getSubMenuList() {
        return subMenuList;
    }

    public void setSubMenuList(List<MenuView> subMenuList) {
        this.subMenuList = subMenuList;
    }

    @Override
    public String toString() {
        return "MenuView{" +
                "menuId=" + menuId +
                ", menuName='" + menuName + '\'' +
                ", menuUrl='" + menuUrl + '\'' +
                ", subMenu=" + subMenuList +
                '}';
    }
}

编写sevice层数据(接口省略,这里只写其实现类):

package com.jiazhong.office.service.rbac.impl;

import com.jiazhong.office.dao.rbac.ModuleDao;
import com.jiazhong.office.model.Module;
import com.jiazhong.office.model.view.MenuView;
import com.jiazhong.office.service.rbac.MainMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: MainMenuServiceImpl
 * @Description: TODO 主菜单生成服务类
 * @Author: JiaShiXi
 * @Date: 2021/2/26 12:46
 * @Version: 1.0
 **/

@Transactional
@Service("mainMenuService")
public class MainMenuServiceImpl implements MainMenuService {

    @Autowired
    private ModuleDao moduleDao;

    @Override
    public List<MenuView> getMenuList(String account_name) {

        //获取从数据库中查到的模块集合
        List<Module> moduleList = moduleDao.getModuleListByAccountName(account_name);
        System.out.println("moduleDao"+moduleList);
        //创建主菜单集合
        List<MenuView> menuViewList = new ArrayList<>();

        //声明一个主菜单变量
        MenuView menuView = null;

        for (Module module : moduleList) {
            /**
             * 如果是第一次循环,menuView == null,创建menuView对象
             * 如果循环>1,menuView!=null,但是menuView中的menuId与module中的父ID不一致,将一个新的MenuView对象赋给menuView
             */
            if (menuView == null || !menuView.getMenuId().equals(module.getP_id())){
                //创建一个主菜单对象赋给主菜单变量
                menuView = new MenuView();

                //设置主菜单的相关属性(主菜单的属性不论循环多少次只需要设置一次,所以只能在创建主菜单对象时设置)
                menuView.setMenuId(module.getP_id());
                menuView.setMenuName(module.getP_name());
                //设置主菜单的子菜单集合(此时子菜单还不确定,所以先new一个空集合)
                menuView.setSubMenuList(new ArrayList<>());
                //添加到主菜单集合中
                menuViewList.add(menuView);
            }

            //创建一个子菜单
            MenuView subMenu = new MenuView();

            //设置子菜单的属性(子菜单每循环一次就需要设置一次)
            subMenu.setMenuId(module.getS_id());
            subMenu.setMenuName(module.getS_name());
            subMenu.setMenuUrl(module.getS_url());

            //将子菜单加入到父菜单中的子菜单集合
            menuView.getSubMenuList().add(subMenu);
        }

        System.out.println("MainMenuService"+menuViewList);

        return menuViewList;
    }
}

编写controller层:

package com.jiazhong.office.controller.rbac;

import com.jiazhong.office.commons.Constant;
import com.jiazhong.office.commons.CurAccount;
import com.jiazhong.office.model.view.MenuView;
import com.jiazhong.office.service.rbac.MainMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;
import java.util.List;

/**
 * @ClassName: MainMenuController
 * @Description: TODO 主菜单生成控制器
 * @Author: JiaShiXi
 * @Date: 2021/2/26 12:41
 * @Version: 1.0
 **/

@RestController
@RequestMapping("/main")
public class MainMenuController {

    @Autowired
    private MainMenuService mainMenuService;

    /**
     * 获取主菜单集合
     * @param session 从session对象中获取存入的账户视图对象
     * @return
     */

    @GetMapping("/getMenuList")
    public List<MenuView> getMenuList(HttpSession session){

        //从session对象中获取存入的账户视图对象
        CurAccount curAccount = (CurAccount) session.getAttribute(Constant.SESSION_CUR_ACCOUNT);

        //获取账户名
        String account_name = curAccount.getAccount_name();

        //从服务层获取主菜单集合
        List<MenuView> menuList = mainMenuService.getMenuList(account_name);

        System.out.println("MainMenuController"+menuList);
        return menuList;
    }
}

这里的有关于后端的权限菜单的数据模型就生成好了,现在我们来写一下前端:

在这里插入图片描述

在这里插入图片描述

最后,测试,admin用户的权限菜单:

在这里插入图片描述

测试成功!

这里需要注意的是,要将数据库tbl_module中的module_url的值改为路由配置url的值!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jackson Xi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值