成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

手把手教你搞定菜單權(quán)限設(shè)計(jì),精確到按鈕級(jí)別,建議收藏

開發(fā) 項(xiàng)目管理
在實(shí)際的項(xiàng)目開發(fā)過程中,菜單權(quán)限功能可以說(shuō)是后端管理系統(tǒng)中必不可少的一個(gè)環(huán)節(jié),根據(jù)業(yè)務(wù)的復(fù)雜度,設(shè)計(jì)的時(shí)候可深可淺,但無(wú)論怎么變化,設(shè)計(jì)的思路基本都是圍繞著用戶、角色、菜單進(jìn)行相應(yīng)的擴(kuò)展。

 一、介紹

在實(shí)際的項(xiàng)目開發(fā)過程中,菜單權(quán)限功能可以說(shuō)是后端管理系統(tǒng)中必不可少的一個(gè)環(huán)節(jié),根據(jù)業(yè)務(wù)的復(fù)雜度,設(shè)計(jì)的時(shí)候可深可淺,但無(wú)論怎么變化,設(shè)計(jì)的思路基本都是圍繞著用戶、角色、菜單進(jìn)行相應(yīng)的擴(kuò)展。

[[331842]]

今天小編就和大家一起來(lái)討論一下,怎么設(shè)計(jì)一套可以精確到按鈕級(jí)別的菜單權(quán)限功能,廢話不多說(shuō),直接開擼!

二、數(shù)據(jù)庫(kù)設(shè)計(jì)

先來(lái)看一下,用戶、角色、菜單表對(duì)應(yīng)的ER圖,如下:

 

其中,用戶和角色是多對(duì)多的關(guān)系,角色與菜單也是多對(duì)多的關(guān)系,用戶通過角色來(lái)關(guān)聯(lián)到菜單,當(dāng)然也有的業(yè)務(wù)系統(tǒng)菜單權(quán)限模型,是可以直接通過用戶關(guān)聯(lián)到菜單,對(duì)菜單權(quán)限可以直接控制到用戶級(jí)別,不過這個(gè)都不是問題,這個(gè)也可以進(jìn)行擴(kuò)展。

對(duì)于用戶、角色表比較簡(jiǎn)單,下面,我們重點(diǎn)來(lái)看看菜單表的設(shè)計(jì),如下:

 

可以看到,整個(gè)菜單表就是一個(gè)樹型結(jié)構(gòu),關(guān)鍵字段說(shuō)明:

  • menu_code:菜單編碼,用于后端權(quán)限控制
  • parent_id:菜單父節(jié)點(diǎn)ID,方便遞歸遍歷菜單
  • node_type:節(jié)點(diǎn)類型,可以是文件夾、頁(yè)面或者按鈕類型
  • link_url:頁(yè)面對(duì)應(yīng)的地址,如果是文件夾或者按鈕類型,可以為空
  • level:菜單樹的層次,以便于查詢指定層級(jí)的菜單
  • path:樹id的路徑,主要用于存放從根節(jié)點(diǎn)到當(dāng)前樹的父節(jié)點(diǎn)的路徑,逗號(hào)分隔,想要找父節(jié)點(diǎn)會(huì)特別快

為了后面方便開發(fā),我們先創(chuàng)建一個(gè)名為menu_auth_db的數(shù)據(jù)庫(kù),初始腳本如下:

  1. CREATE DATABASE IF NOT EXISTS menu_auth_db default charset utf8mb4 COLLATE utf8mb4_unicode_ci; 
  2.  
  3. CREATE TABLE menu_auth_db.tb_user ( 
  4.   id bigint(20) unsigned NOT NULL COMMENT '消息給過來(lái)的ID'
  5.   mobile varchar(20) NOT NULL DEFAULT '' COMMENT '手機(jī)號(hào)'
  6.   name varchar(100) NOT NULL DEFAULT '' COMMENT '姓名'
  7.   password varchar(128) NOT NULL DEFAULT '' COMMENT '密碼'
  8.   is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除 1:已刪除;0:未刪除'
  9.   PRIMARY KEY (id), 
  10.   KEY idx_name (name) USING BTREE, 
  11.   KEY idx_mobile (mobile) USING BTREE 
  12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用戶表'
  13.  
  14. CREATE TABLE menu_auth_db.tb_user_role ( 
  15.   id bigint(20) unsigned NOT NULL COMMENT '主鍵'
  16.   user_id bigint(20) NOT NULL COMMENT '用戶ID'
  17.   role_id bigint(20) NOT NULL COMMENT '角色I(xiàn)D'
  18.   PRIMARY KEY (id), 
  19.   KEY idx_user_id (user_id) USING BTREE, 
  20.   KEY idx_role_id (role_id) USING BTREE 
  21. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用戶角色表'
  22.  
  23. CREATE TABLE menu_auth_db.tb_role ( 
  24.   id bigint(20) unsigned NOT NULL COMMENT '主鍵'
  25.   code varchar(100) NOT NULL DEFAULT '' COMMENT '編碼'
  26.   name varchar(100) NOT NULL DEFAULT '' COMMENT '名稱'
  27.   is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除 1:已刪除;0:未刪除'
  28.   PRIMARY KEY (id), 
  29.   KEY idx_code (code) USING BTREE, 
  30.   KEY idx_name (name) USING BTREE 
  31. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色表'
  32.  
  33.  
  34. CREATE TABLE menu_auth_db.tb_role_menu ( 
  35.   id bigint(20) unsigned NOT NULL COMMENT '主鍵'
  36.   role_id bigint(20) NOT NULL COMMENT '角色I(xiàn)D'
  37.   menu_id bigint(20) NOT NULL COMMENT '菜單ID'
  38.   PRIMARY KEY (id), 
  39.   KEY idx_role_id (role_id) USING BTREE, 
  40.   KEY idx_menu_id (menu_id) USING BTREE 
  41. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色菜單關(guān)系表'
  42.  
  43.  
  44. CREATE TABLE menu_auth_db.tb_menu ( 
  45.   id bigint(20) NOT NULL COMMENT '主鍵'
  46.   name varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名稱'
  47.   menu_code varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '菜單編碼'
  48.   parent_id bigint(20) DEFAULT NULL COMMENT '父節(jié)點(diǎn)'
  49.   node_type tinyint(4) NOT NULL DEFAULT '1' COMMENT '節(jié)點(diǎn)類型,1文件夾,2頁(yè)面,3按鈕'
  50.   icon_url varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '圖標(biāo)地址'
  51.   sort int(11) NOT NULL DEFAULT '1' COMMENT '排序號(hào)'
  52.   link_url varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '頁(yè)面對(duì)應(yīng)的地址'
  53.   level int(11) NOT NULL DEFAULT '0' COMMENT '層次'
  54.   path varchar(2500) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '樹id的路徑 整個(gè)層次上的路徑id,逗號(hào)分隔,想要找父節(jié)點(diǎn)特別快'
  55.   is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除 1:已刪除;0:未刪除'
  56.   PRIMARY KEY (id) USING BTREE, 
  57.   KEY idx_parent_id (parent_id) USING BTREE 
  58. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='菜單表'

三、后端開發(fā)

菜單權(quán)限模塊的數(shù)據(jù)庫(kù)設(shè)計(jì),一般5張表就可以搞定,真正有點(diǎn)復(fù)雜的地方在于數(shù)據(jù)的寫入和渲染,當(dāng)然如果老板突然讓你來(lái)開發(fā)一套菜單權(quán)限系統(tǒng),我們也沒必要慌張,下面,我們一起來(lái)看看后端應(yīng)該如何開發(fā)。

3.1、創(chuàng)建項(xiàng)目

為了方便快捷,小編我采用的是springboot+mybatisPlus組件來(lái)快速開發(fā),直接利用mybatisPlus官方提供的快速生成代碼的demo,一鍵生成所需的dao、service、web層的代碼,結(jié)果如下:

 

3.2、編寫菜單添加服務(wù)

  1. @Override 
  2. public void addMenu(Menu menu) { 
  3.     //如果插入的當(dāng)前節(jié)點(diǎn)為根節(jié)點(diǎn),parentId指定為0 
  4.     if(menu.getParentId().longValue() == 0){ 
  5.         menu.setLevel(1);//根節(jié)點(diǎn)層級(jí)為1 
  6.         menu.setPath(null);//根節(jié)點(diǎn)路徑為空 
  7.     }else
  8.         Menu parentMenu = baseMapper.selectById(menu.getParentId()); 
  9.         if(parentMenu == null){ 
  10.             throw new CommonException("未查詢到對(duì)應(yīng)的父節(jié)點(diǎn)"); 
  11.         } 
  12.         menu.setLevel(parentMenu.getLevel().intValue() + 1); 
  13.         if(StringUtils.isNotEmpty(parentMenu.getPath())){ 
  14.             menu.setPath(parentMenu.getPath() + "," + parentMenu.getId()); 
  15.         }else
  16.             menu.setPath(parentMenu.getId().toString()); 
  17.         } 
  18.     } 
  19.     //可以使用雪花算法,生成ID 
  20.     menu.setId(System.currentTimeMillis()); 
  21.     super.save(menu); 

新增菜單比較簡(jiǎn)單,直接將數(shù)據(jù)插入即可,需要注意的地方是parent_id、level、path,這三個(gè)字段的寫入,如果新建的是根節(jié)點(diǎn),默認(rèn)parent_id為0,方便后續(xù)遞歸遍歷。

3.3、編寫菜單后端查詢服務(wù)

  • 新建一個(gè)菜單視圖實(shí)體類
  1. @Data 
  2. @EqualsAndHashCode(callSuper = false
  3. @Accessors(chain = true
  4. public class MenuVo implements Serializable { 
  5.  
  6.     private static final long serialVersionUID = -4559267810907997111L; 
  7.  
  8.     /** 
  9.      * 主鍵 
  10.      */ 
  11.     private Long id; 
  12.  
  13.     /** 
  14.      * 名稱 
  15.      */ 
  16.     private String name
  17.  
  18.     /** 
  19.      * 菜單編碼 
  20.      */ 
  21.     private String menuCode; 
  22.  
  23.     /** 
  24.      * 父節(jié)點(diǎn) 
  25.      */ 
  26.     private Long parentId; 
  27.  
  28.     /** 
  29.      * 節(jié)點(diǎn)類型,1文件夾,2頁(yè)面,3按鈕 
  30.      */ 
  31.     private Integer nodeType; 
  32.  
  33.     /** 
  34.      * 圖標(biāo)地址 
  35.      */ 
  36.     private String iconUrl; 
  37.  
  38.     /** 
  39.      * 排序號(hào) 
  40.      */ 
  41.     private Integer sort; 
  42.  
  43.     /** 
  44.      * 頁(yè)面對(duì)應(yīng)的地址 
  45.      */ 
  46.     private String linkUrl; 
  47.  
  48.     /** 
  49.      * 層次 
  50.      */ 
  51.     private Integer level
  52.  
  53.     /** 
  54.      * 樹id的路徑 整個(gè)層次上的路徑id,逗號(hào)分隔,想要找父節(jié)點(diǎn)特別快 
  55.      */ 
  56.     private String path; 
  57.  
  58.     /** 
  59.      * 子菜單集合 
  60.      */ 
  61.     List<MenuVo> childMenu; 
  • 編寫菜單查詢服務(wù),使用遞歸重新封裝菜單視圖
  1. @Override 
  2. public List<MenuVo> queryMenuTree() { 
  3.     Wrapper queryObj = new QueryWrapper<>().orderByAsc("level","sort"); 
  4.     List<Menu> allMenu = super.list(queryObj); 
  5.  // 0L:表示根節(jié)點(diǎn)的父ID 
  6.     List<MenuVo> resultList = transferMenuVo(allMenu, 0L); 
  7.     return resultList; 
  8. /** 
  9.  * 封裝菜單視圖 
  10.  * @param allMenu 
  11.  * @param parentId 
  12.  * @return 
  13.  */ 
  14. private List<MenuVo> transferMenuVo(List<Menu> allMenu, Long parentId){ 
  15.     List<MenuVo> resultList = new ArrayList<>(); 
  16.     if(!CollectionUtils.isEmpty(allMenu)){ 
  17.         for (Menu source : allMenu) { 
  18.             if(parentId.longValue() == source.getParentId().longValue()){ 
  19.                 MenuVo menuVo = new MenuVo(); 
  20.                 BeanUtils.copyProperties(source, menuVo); 
  21.                 //遞歸查詢子菜單,并封裝信息 
  22.                 List<MenuVo> childList = transferMenuVo(allMenu, source.getId()); 
  23.                 if(!CollectionUtils.isEmpty(childList)){ 
  24.                     menuVo.setChildMenu(childList); 
  25.                 } 
  26.                 resultList.add(menuVo); 
  27.             } 
  28.         } 
  29.     } 
  30.     return resultList; 

編寫一個(gè)菜單樹查詢接口,如下:

  1. @RestController 
  2. @RequestMapping("/menu"
  3. public class MenuController { 
  4.  
  5.     @Autowired 
  6.     private MenuService menuService; 
  7.  
  8.     @PostMapping(value = "/queryMenuTree"
  9.     public List<MenuVo> queryTreeMenu(){ 
  10.         return menuService.queryMenuTree(); 
  11.     } 

為了便于演示,我們先初始化7條數(shù)據(jù),如下圖:

 

其中最后三條是按鈕類型,等下會(huì)用于后端權(quán)限控制,接口查詢結(jié)果如下:

 

這個(gè)服務(wù)是針對(duì)后端管理界面查詢的,會(huì)將所有的菜單全部查詢出來(lái)以便于進(jìn)行管理,展示結(jié)果類似如下圖:

 

這個(gè)圖片截圖于小編正在開發(fā)的一個(gè)項(xiàng)目,內(nèi)容可能不一致,但是數(shù)據(jù)結(jié)構(gòu)基本都是一致的。

3.4、編寫用戶菜單權(quán)限查詢服務(wù)

在上面,我們介紹到了用戶通過角色來(lái)關(guān)聯(lián)菜單,因此,很容易想到,流程如下:

  • 第一步:先通過用戶查詢到對(duì)應(yīng)的角色;
  • 第二步:然后再通過角色查詢到對(duì)應(yīng)的菜單;
  • 第三步:最后將菜單查詢出來(lái)之后進(jìn)行渲染;

實(shí)現(xiàn)過程相比菜單查詢服務(wù)多了前2個(gè)步驟,過程如下:

  1. @Override 
  2. public List<MenuVo> queryMenus(Long userId) { 
  3.     //1、先查詢當(dāng)前用戶對(duì)應(yīng)的角色 
  4.     Wrapper queryUserRoleObj = new QueryWrapper<>().eq("user_id", userId); 
  5.     List<UserRole> userRoles = userRoleService.list(queryUserRoleObj); 
  6.     if(!CollectionUtils.isEmpty(userRoles)){ 
  7.         //2、通過角色查詢菜單(默認(rèn)取第一個(gè)角色) 
  8.         Wrapper queryRoleMenuObj = new QueryWrapper<>().eq("role_id", userRoles.get(0).getRoleId()); 
  9.         List<RoleMenu> roleMenus = roleMenuService.list(queryRoleMenuObj); 
  10.         if(!CollectionUtils.isEmpty(roleMenus)){ 
  11.             Set<Long> menuIds = new HashSet<>(); 
  12.             for (RoleMenu roleMenu : roleMenus) { 
  13.                 menuIds.add(roleMenu.getMenuId()); 
  14.             } 
  15.             //查詢對(duì)應(yīng)的菜單 
  16.             Wrapper queryMenuObj = new QueryWrapper<>().in("id", new ArrayList<>(menuIds)); 
  17.             List<Menu> menus = super.list(queryMenuObj); 
  18.             if(!CollectionUtils.isEmpty(menus)){ 
  19.                 //將菜單下對(duì)應(yīng)的父節(jié)點(diǎn)也一并全部查詢出來(lái) 
  20.                 Set<Long> allMenuIds = new HashSet<>(); 
  21.                 for (Menu menu : menus) { 
  22.                     allMenuIds.add(menu.getId()); 
  23.                     if(StringUtils.isNotEmpty(menu.getPath())){ 
  24.                         String[] pathIds = StringUtils.split(",", menu.getPath()); 
  25.                         for (String pathId : pathIds) { 
  26.                             allMenuIds.add(Long.valueOf(pathId)); 
  27.                         } 
  28.                     } 
  29.                 } 
  30.                 //3、查詢對(duì)應(yīng)的所有菜單,并進(jìn)行封裝展示 
  31.                 List<Menu> allMenus = super.list(new QueryWrapper<Menu>().in("id", new ArrayList<>(allMenuIds))); 
  32.                 List<MenuVo> resultList = transferMenuVo(allMenus, 0L); 
  33.                 return resultList; 
  34.             } 
  35.         } 
  36.  
  37.     } 
  38.     return null
  • 編寫一個(gè)用戶菜單查詢接口,如下:
  1. @PostMapping(value = "/queryMenus"
  2. public List<MenuVo> queryMenus(Long userId){ 
  3.  //查詢當(dāng)前用戶下的菜單權(quán)限 
  4.     return menuService.queryMenus(userId); 

有的同學(xué),可能覺得沒必要存放path這個(gè)字段,的確在某些場(chǎng)景下不需要。

為什么要存放這個(gè)字段呢?

小編在跟前端進(jìn)行對(duì)接的時(shí)候,發(fā)現(xiàn)這么一個(gè)問題,有些前端的樹型組件,在勾選子集的時(shí)候,不會(huì)將對(duì)應(yīng)的父ID傳給后端,例如,我在勾選【列表查詢】的時(shí)候,前端無(wú)法將父節(jié)點(diǎn)【菜單管理】ID也傳給后端,所有后端實(shí)際存放的是一個(gè)尾節(jié)點(diǎn),需要一個(gè)字段path,來(lái)存放節(jié)點(diǎn)對(duì)應(yīng)的父節(jié)點(diǎn)路徑。

 

其實(shí),前端也可以傳,只不過需要修改組件的屬性,前端修改完成之后,樹型組件就無(wú)法全選,不滿足業(yè)務(wù)需求。

所以,有些時(shí)候得根據(jù)實(shí)際得情況來(lái)進(jìn)行取舍。

3.5、編寫后端權(quán)限控制

后端進(jìn)行權(quán)限控制目標(biāo),主要是為了防止無(wú)權(quán)限的用戶,進(jìn)行接口請(qǐng)求查詢。

其中菜單編碼menuCode就是一個(gè)前、后端聯(lián)系的橋梁,細(xì)心的你會(huì)發(fā)現(xiàn),所有后端的接口,與前端對(duì)應(yīng)的都是按鈕操作,所以我們可以以按鈕為基準(zhǔn),實(shí)現(xiàn)前后端雙向控制。

以【角色管理-查詢】這個(gè)為例,前端可以通過菜單編碼實(shí)現(xiàn)是否展示這個(gè)查詢按鈕,后端可以通過菜單編碼來(lái)判斷,當(dāng)前用戶是否具備請(qǐng)求接口的權(quán)限。

以后端為例,我們只需編寫一個(gè)權(quán)限注解和代理攔截器即可!

  • 編寫一個(gè)權(quán)限注解
  1. @Target({ElementType.TYPE, ElementType.METHOD}) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. public @interface CheckPermissions { 
  4.  
  5.     String value() default ""
  • 編寫一個(gè)代理攔截器,攔截有@CheckPermissions注解的方法
  1. @Aspect 
  2. @Component 
  3. public class CheckPermissionsAspect { 
  4.  
  5.     @Autowired 
  6.     private MenuMapper menuMapper; 
  7.  
  8.     @Pointcut("@annotation(com.company.project.core.annotation.CheckPermissions)"
  9.     public void checkPermissions() {} 
  10.  
  11.     @Before("checkPermissions()"
  12.     public void doBefore(JoinPoint joinPoint) throws Throwable { 
  13.         Long userId = null
  14.         Object[] args = joinPoint.getArgs(); 
  15.         Object parobj = args[0]; 
  16.         //用戶請(qǐng)求參數(shù)實(shí)體類中的用戶ID 
  17.         if(!Objects.isNull(parobj)){ 
  18.             Class userCla = parobj.getClass(); 
  19.             Field field = userCla.getDeclaredField("userId"); 
  20.             field.setAccessible(true); 
  21.             userId = (Long) field.get(parobj); 
  22.         } 
  23.         if(!Objects.isNull(userId)){ 
  24.             //獲取方法上有CheckPermissions注解的參數(shù) 
  25.             Class clazz = joinPoint.getTarget().getClass(); 
  26.             String methodName = joinPoint.getSignature().getName(); 
  27.             Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes(); 
  28.             Method method = clazz.getMethod(methodName, parameterTypes); 
  29.             if(method.getAnnotation(CheckPermissions.class) != null){ 
  30.                 CheckPermissions annotation = method.getAnnotation(CheckPermissions.class); 
  31.                 String menuCode = annotation.value(); 
  32.                 if (StringUtils.isNotBlank(menuCode)) { 
  33.                     //通過用戶ID、菜單編碼查詢是否有關(guān)聯(lián) 
  34.                     int count = menuMapper.selectAuthByUserIdAndMenuCode(userId, menuCode); 
  35.                     if(count == 0){ 
  36.                         throw new CommonException("接口無(wú)訪問權(quán)限"); 
  37.                     } 
  38.                 } 
  39.             } 
  40.         } 
  41.     } 
  • 我們以【角色管理-查詢】為例,先新建一個(gè)請(qǐng)求實(shí)體類RoleDto,添加用戶ID屬性
  1. @Data 
  2. @EqualsAndHashCode(callSuper = false
  3. @Accessors(chain = true
  4. public class RoleDto extends Role { 
  5.  
  6.  //添加用戶ID 
  7.     private Long userId; 
  • 在需要的接口上,添加@CheckPermissions注解,增加權(quán)限控制
  1. @RestController 
  2. @RequestMapping("/role"
  3. public class RoleController { 
  4.  
  5.     private RoleService roleService; 
  6.  
  7.     @CheckPermissions(value="roleMgr:list"
  8.     @PostMapping(value = "/queryRole"
  9.     public List<Role> queryRole(RoleDto roleDto){ 
  10.         return roleService.list(); 
  11.     } 
  12.  
  13.     @CheckPermissions(value="roleMgr:add"
  14.     @PostMapping(value = "/addRole"
  15.     public void addRole(RoleDto roleDto){ 
  16.         roleService.add(roleDto); 
  17.     } 
  18.  
  19.     @CheckPermissions(value="roleMgr:delete"
  20.     @PostMapping(value = "/deleteRole"
  21.     public void deleteRole(RoleDto roleDto){ 
  22.         roleService.delete(roleDto); 
  23.     } 

依次類推,當(dāng)我們想對(duì)某個(gè)接口進(jìn)行權(quán)限控制的時(shí)候,只需要添加一個(gè)注解@CheckPermissions,并填寫對(duì)應(yīng)的菜單編碼即可!

四、用戶權(quán)限

測(cè)試我們先初始化一個(gè)用戶【張三】,然后給他分配一個(gè)角色【訪客人員】,同時(shí)給這個(gè)角色分配一下2個(gè)菜單權(quán)限【系統(tǒng)配置】、【用戶管理】,等會(huì)用于權(quán)限測(cè)試。

初始內(nèi)容如下:

 

數(shù)據(jù)初始化完成之后,我們來(lái)啟動(dòng)項(xiàng)目,傳入用戶【張三】的ID,查詢用戶具備的菜單權(quán)限,結(jié)果如下:

 

 

查詢結(jié)果,用戶【張三】有兩個(gè)菜單權(quán)限!

接著,我們來(lái)驗(yàn)證一下,用戶【張三】是否有角色查詢權(quán)限,請(qǐng)求角色查詢接口如下:

 

因?yàn)闆]有配置角色查詢接口,所以無(wú)權(quán)訪問!

五、總結(jié)

整片內(nèi)容,只介紹了后端關(guān)鍵的服務(wù)實(shí)現(xiàn)過程,可能也有遺漏的地方,歡迎網(wǎng)友點(diǎn)評(píng)、吐槽!

 

責(zé)任編輯:武曉燕 來(lái)源: Java極客技術(shù)
相關(guān)推薦

2018-03-23 20:45:23

機(jī)器學(xué)習(xí)NLP文本數(shù)據(jù)

2020-12-08 10:32:15

Python郵件tcp

2011-01-10 14:41:26

2025-05-07 00:31:30

2011-05-03 15:59:00

黑盒打印機(jī)

2022-02-23 20:53:54

數(shù)據(jù)清洗模型

2021-07-14 09:00:00

JavaFX開發(fā)應(yīng)用

2020-12-07 09:01:58

冪等系統(tǒng)f(f(x)) =f(

2021-06-08 09:49:01

協(xié)程池Golang設(shè)計(jì)

2011-02-22 13:46:27

微軟SQL.NET

2021-02-26 11:54:38

MyBatis 插件接口

2021-12-28 08:38:26

Linux 中斷喚醒系統(tǒng)Linux 系統(tǒng)

2022-03-14 14:47:21

HarmonyOS操作系統(tǒng)鴻蒙

2022-07-27 08:16:22

搜索引擎Lucene

2022-01-08 20:04:20

攔截系統(tǒng)調(diào)用

2023-04-26 12:46:43

DockerSpringKubernetes

2022-12-07 08:42:35

2020-07-23 14:39:28

系統(tǒng)權(quán)限設(shè)計(jì)

2021-12-17 18:21:54

大數(shù)據(jù)流水線設(shè)計(jì)

2021-12-10 18:19:55

指標(biāo)體系設(shè)計(jì)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产精品福利视频 | 久久国内| 午夜性视频 | 成人精品一区二区三区中文字幕 | 91九色porny首页最多播放 | 日本公妇乱淫xxxⅹ 国产在线不卡 | 毛片免费在线观看 | 一区二区视频在线 | 亚洲一区电影 | 91国自视频| 亚洲午夜av | 国产探花在线精品一区二区 | 精品一级 | 亚洲性人人天天夜夜摸 | 酒色成人网 | 色爱综合网 | 亚洲午夜精品久久久久久app | 欧美精品91 | 久久久青草婷婷精品综合日韩 | 亚洲精品久久久久中文字幕二区 | 丁香婷婷综合激情五月色 | 日日干日日操 | 精品欧美一区免费观看α√ | 久久成人免费 | 国产色| 精品国产乱码久久久久久老虎 | 欧美一级在线观看 | 正在播放国产精品 | 偷拍自拍网站 | 国产91丝袜 | 涩爱av一区二区三区 | 久久久精品一区 | 亚洲精品一区二区 | 国产精品福利视频 | 国产福利在线免费观看 | 亚洲精品久久久一区二区三区 | 国外成人在线视频 | 一区二区三区精品在线 | 成人av一区二区三区 | 一区二区三区国产好 | 人人爽人人爽人人片av |