Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
有来技术
youlai-mall
提交
9f30696a
Y
youlai-mall
项目概览
有来技术
/
youlai-mall
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Y
youlai-mall
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
9f30696a
编写于
11月 04, 2023
作者:
郝
郝先瑞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 菜单路由优化
上级
8ee68bf8
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
180 addition
and
119 deletion
+180
-119
youlai-system/system-boot/src/main/java/com/youlai/system/model/bo/RouteBO.java
...oot/src/main/java/com/youlai/system/model/bo/RouteBO.java
+12
-2
youlai-system/system-boot/src/main/java/com/youlai/system/model/entity/SysMenu.java
...src/main/java/com/youlai/system/model/entity/SysMenu.java
+10
-0
youlai-system/system-boot/src/main/java/com/youlai/system/model/form/MenuForm.java
.../src/main/java/com/youlai/system/model/form/MenuForm.java
+6
-0
youlai-system/system-boot/src/main/java/com/youlai/system/model/vo/RouteVO.java
...oot/src/main/java/com/youlai/system/model/vo/RouteVO.java
+7
-2
youlai-system/system-boot/src/main/java/com/youlai/system/service/impl/SysMenuServiceImpl.java
...va/com/youlai/system/service/impl/SysMenuServiceImpl.java
+140
-112
youlai-system/system-boot/src/main/resources/mapper/SysMenuMapper.xml
...m/system-boot/src/main/resources/mapper/SysMenuMapper.xml
+5
-3
未找到文件。
youlai-system/system-boot/src/main/java/com/youlai/system/model/bo/RouteBO.java
浏览文件 @
9f30696a
...
...
@@ -64,13 +64,23 @@ public class RouteBO {
private
String
icon
;
/**
*
外链
路径
*
跳转
路径
*/
private
String
redirect
Url
;
private
String
redirect
;
/**
* 拥有路由的权限
*/
private
List
<
String
>
roles
;
/**
* 【目录】只有一个子路由是否始终显示(1:是 0:否)
*/
private
Integer
alwaysShow
;
/**
* 【菜单】是否开启页面缓存(1:是 0:否)
*/
private
Integer
keepAlive
;
}
\ No newline at end of file
youlai-system/system-boot/src/main/java/com/youlai/system/model/entity/SysMenu.java
浏览文件 @
9f30696a
...
...
@@ -77,4 +77,14 @@ public class SysMenu extends BaseEntity {
*/
private
String
treePath
;
/**
* 【菜单】是否开启页面缓存(1:开启;0:关闭)
*/
private
Integer
keepAlive
;
/**
* 【目录】只有一个子路由是否始终显示(1:是 0:否)
*/
private
Integer
alwaysShow
;
}
\ No newline at end of file
youlai-system/system-boot/src/main/java/com/youlai/system/model/form/MenuForm.java
浏览文件 @
9f30696a
...
...
@@ -41,4 +41,10 @@ public class MenuForm {
@Schema
(
description
=
"跳转路径"
)
private
String
redirect
;
@Schema
(
description
=
"【菜单】是否开启页面缓存"
,
example
=
"1"
)
private
Integer
keepAlive
;
@Schema
(
description
=
"【目录】只有一个子路由是否始终显示"
,
example
=
"1"
)
private
Integer
alwaysShow
;
}
youlai-system/system-boot/src/main/java/com/youlai/system/model/vo/RouteVO.java
浏览文件 @
9f30696a
...
...
@@ -42,14 +42,19 @@ public class RouteVO {
@Schema
(
description
=
"ICON"
)
private
String
icon
;
@Schema
(
description
=
"是否隐藏"
,
example
=
"true"
)
@Schema
(
description
=
"是否隐藏
(true-是 false-否)
"
,
example
=
"true"
)
private
Boolean
hidden
;
@Schema
(
description
=
"拥有路由权限的角色编码"
,
example
=
"['ADMIN','ROOT']"
)
private
List
<
String
>
roles
;
@Schema
(
description
=
"是否开启缓存"
,
example
=
"true"
)
@Schema
(
description
=
"【菜单】是否开启页面缓存"
,
example
=
"true"
)
@JsonInclude
(
JsonInclude
.
Include
.
NON_NULL
)
private
Boolean
keepAlive
;
@Schema
(
description
=
"【目录】只有一个子路由是否始终显示"
,
example
=
"true"
)
@JsonInclude
(
JsonInclude
.
Include
.
NON_NULL
)
private
Boolean
alwaysShow
;
}
@Schema
(
description
=
"子路由列表"
)
...
...
youlai-system/system-boot/src/main/java/com/youlai/system/service/impl/SysMenuServiceImpl.java
浏览文件 @
9f30696a
...
...
@@ -39,7 +39,6 @@ import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public
class
SysMenuServiceImpl
extends
ServiceImpl
<
SysMenuMapper
,
SysMenu
>
implements
SysMenuService
{
private
final
MenuConverter
menuConverter
;
/**
...
...
@@ -57,43 +56,40 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
Set
<
Long
>
parentIds
=
menus
.
stream
()
.
map
(
SysMenu:
:
getParentId
)
.
collect
(
Collectors
.
toSet
());
Set
<
Long
>
menuIds
=
menus
.
stream
()
.
map
(
SysMenu:
:
getId
)
.
collect
(
Collectors
.
toSet
());
List
<
Long
>
rootIds
=
CollectionUtil
.
subtractToList
(
parentIds
,
menuIds
);
// 求差集,得到 parentIds 中 menuIds 没有的元素
// 获取根节点ID
List
<
Long
>
rootIds
=
parentIds
.
stream
()
.
filter
(
id
->
!
menuIds
.
contains
(
id
))
.
toList
();
List
<
MenuVO
>
list
=
new
ArrayList
<>();
for
(
Long
rootId
:
rootIds
)
{
list
.
addAll
(
recurMenus
(
rootId
,
menus
));
// 递归
}
return
list
;
// 使用递归函数来构建菜单树
List
<
MenuVO
>
menuList
=
rootIds
.
stream
()
.
flatMap
(
rootId
->
buildMenuTree
(
rootId
,
menus
).
stream
())
.
collect
(
Collectors
.
toList
());
return
menuList
;
}
/**
* 保存菜单
* 递归生成菜单列表
*
* @param parentId 父级ID
* @param menuList 菜单列表
* @return 菜单列表
*/
@Override
public
boolean
saveMenu
(
MenuForm
menuForm
)
{
String
path
=
menuForm
.
getPath
();
MenuTypeEnum
menuType
=
menuForm
.
getType
();
// 菜单类型
switch
(
menuType
)
{
case
CATALOG
->
{
// 目录
if
(
ObjectUtil
.
equal
(
menuForm
.
getParentId
(),
0
)
&&
!
path
.
startsWith
(
"/"
))
{
menuForm
.
setPath
(
"/"
+
path
);
// 一级目录需以 / 开头
}
menuForm
.
setComponent
(
"Layout"
);
}
case
EXTLINK
->
// 外链
menuForm
.
setComponent
(
null
);
}
SysMenu
entity
=
menuConverter
.
form2Entity
(
menuForm
);
String
treePath
=
generateMenuTreePath
(
menuForm
.
getParentId
());
entity
.
setTreePath
(
treePath
);
return
this
.
saveOrUpdate
(
entity
);
private
List
<
MenuVO
>
buildMenuTree
(
Long
parentId
,
List
<
SysMenu
>
menuList
)
{
return
CollectionUtil
.
emptyIfNull
(
menuList
)
.
stream
()
.
filter
(
menu
->
menu
.
getParentId
().
equals
(
parentId
))
.
map
(
entity
->
{
MenuVO
menuVO
=
menuConverter
.
entity2Vo
(
entity
);
List
<
MenuVO
>
children
=
buildMenuTree
(
entity
.
getId
(),
menuList
);
menuVO
.
setChildren
(
children
);
return
menuVO
;
}).
toList
();
}
/**
...
...
@@ -102,17 +98,41 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
@Override
public
List
<
Option
>
listMenuOptions
()
{
List
<
SysMenu
>
menuList
=
this
.
list
(
new
LambdaQueryWrapper
<
SysMenu
>().
orderByAsc
(
SysMenu:
:
getSort
));
return
recurMenuOptions
(
SystemConstants
.
ROOT_NODE_ID
,
menuList
);
return
buildMenuOptions
(
SystemConstants
.
ROOT_NODE_ID
,
menuList
);
}
/**
* 递归生成菜单下拉层级列表
*
* @param parentId 父级ID
* @param menuList 菜单列表
* @return 菜单下拉列表
*/
private
List
<
Option
>
buildMenuOptions
(
Long
parentId
,
List
<
SysMenu
>
menuList
)
{
List
<
Option
>
menuOptions
=
new
ArrayList
<>();
for
(
SysMenu
menu
:
menuList
)
{
if
(
menu
.
getParentId
().
equals
(
parentId
))
{
Option
option
=
new
Option
(
menu
.
getId
(),
menu
.
getName
());
List
<
Option
>
subMenuOptions
=
buildMenuOptions
(
menu
.
getId
(),
menuList
);
if
(!
subMenuOptions
.
isEmpty
())
{
option
.
setChildren
(
subMenuOptions
);
}
menuOptions
.
add
(
option
);
}
}
return
menuOptions
;
}
/**
* 路由列表
*/
@Override
//
@Cacheable(cacheNames = "system", key = "'routes'")
@Cacheable
(
cacheNames
=
"system"
,
key
=
"'routes'"
)
public
List
<
RouteVO
>
listRoutes
()
{
List
<
RouteBO
>
menuList
=
this
.
baseMapper
.
listRoutes
();
return
recur
Routes
(
SystemConstants
.
ROOT_NODE_ID
,
menuList
);
return
build
Routes
(
SystemConstants
.
ROOT_NODE_ID
,
menuList
);
}
/**
...
...
@@ -120,34 +140,96 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
*
* @param parentId 父级ID
* @param menuList 菜单列表
* @return
* @return
路由层级列表
*/
private
List
<
RouteVO
>
recurRoutes
(
Long
parentId
,
List
<
RouteBO
>
menuList
)
{
return
CollectionUtil
.
emptyIfNull
(
menuList
).
stream
()
.
filter
(
menu
->
menu
.
getParentId
().
equals
(
parentId
))
.
map
(
menu
->
{
RouteVO
routeVO
=
new
RouteVO
();
MenuTypeEnum
menuTypeEnum
=
menu
.
getType
();
if
(
MenuTypeEnum
.
MENU
.
equals
(
menuTypeEnum
))
{
String
routeName
=
StringUtils
.
capitalize
(
StrUtil
.
toCamelCase
(
menu
.
getPath
(),
'-'
));
// 路由 name 需要驼峰,首字母大写
routeVO
.
setName
(
routeName
);
// 根据name路由跳转 this.$router.push({name:xxx})
}
routeVO
.
setPath
(
menu
.
getPath
());
// 根据path路由跳转 this.$router.push({path:xxx})
routeVO
.
setRedirect
(
menu
.
getRedirectUrl
());
routeVO
.
setComponent
(
menu
.
getComponent
());
RouteVO
.
Meta
meta
=
new
RouteVO
.
Meta
();
meta
.
setTitle
(
menu
.
getName
());
meta
.
setIcon
(
menu
.
getIcon
());
meta
.
setRoles
(
menu
.
getRoles
());
meta
.
setHidden
(
StatusEnum
.
DISABLE
.
getValue
().
equals
(
menu
.
getVisible
()));
meta
.
setKeepAlive
(
true
);
routeVO
.
setMeta
(
meta
);
List
<
RouteVO
>
children
=
recurRoutes
(
menu
.
getId
(),
menuList
);
private
List
<
RouteVO
>
buildRoutes
(
Long
parentId
,
List
<
RouteBO
>
menuList
)
{
List
<
RouteVO
>
routeList
=
new
ArrayList
<>();
for
(
RouteBO
menu
:
menuList
)
{
if
(
menu
.
getParentId
().
equals
(
parentId
))
{
RouteVO
routeVO
=
toRouteVo
(
menu
);
List
<
RouteVO
>
children
=
buildRoutes
(
menu
.
getId
(),
menuList
);
if
(!
children
.
isEmpty
())
{
routeVO
.
setChildren
(
children
);
return
routeVO
;
}).
toList
();
}
routeList
.
add
(
routeVO
);
}
}
return
routeList
;
}
/**
* 根据RouteBO创建RouteVO
*/
private
RouteVO
toRouteVo
(
RouteBO
routeBO
)
{
RouteVO
routeVO
=
new
RouteVO
();
String
routeName
=
StringUtils
.
capitalize
(
StrUtil
.
toCamelCase
(
routeBO
.
getPath
(),
'-'
));
// 路由 name 需要驼峰,首字母大写
routeVO
.
setName
(
routeName
);
// 根据name路由跳转 this.$router.push({name:xxx})
routeVO
.
setPath
(
routeBO
.
getPath
());
// 根据path路由跳转 this.$router.push({path:xxx})
routeVO
.
setRedirect
(
routeBO
.
getRedirect
());
routeVO
.
setComponent
(
routeBO
.
getComponent
());
RouteVO
.
Meta
meta
=
new
RouteVO
.
Meta
();
meta
.
setTitle
(
routeBO
.
getName
());
meta
.
setIcon
(
routeBO
.
getIcon
());
meta
.
setRoles
(
routeBO
.
getRoles
());
meta
.
setHidden
(
StatusEnum
.
DISABLE
.
getValue
().
equals
(
routeBO
.
getVisible
()));
// 【菜单】是否开启页面缓存
if
(
MenuTypeEnum
.
MENU
.
equals
(
routeBO
.
getType
())
&&
ObjectUtil
.
equals
(
routeBO
.
getKeepAlive
(),
1
))
{
meta
.
setKeepAlive
(
true
);
}
// 【目录】只有一个子路由是否始终显示
if
(
MenuTypeEnum
.
CATALOG
.
equals
(
routeBO
.
getType
())
&&
ObjectUtil
.
equals
(
routeBO
.
getAlwaysShow
(),
1
))
{
meta
.
setAlwaysShow
(
true
);
}
routeVO
.
setMeta
(
meta
);
return
routeVO
;
}
/**
* 保存菜单
*/
@Override
public
boolean
saveMenu
(
MenuForm
menuForm
)
{
String
path
=
menuForm
.
getPath
();
MenuTypeEnum
menuType
=
menuForm
.
getType
();
// 如果是目录
if
(
menuType
==
MenuTypeEnum
.
CATALOG
)
{
if
(
menuForm
.
getParentId
()
==
0
&&
!
path
.
startsWith
(
"/"
))
{
menuForm
.
setPath
(
"/"
+
path
);
// 一级目录需以 / 开头
}
menuForm
.
setComponent
(
"Layout"
);
}
// 如果是外链
else
if
(
menuType
==
MenuTypeEnum
.
EXTLINK
)
{
menuForm
.
setComponent
(
null
);
}
SysMenu
entity
=
menuConverter
.
form2Entity
(
menuForm
);
String
treePath
=
generateMenuTreePath
(
menuForm
.
getParentId
());
entity
.
setTreePath
(
treePath
);
return
this
.
saveOrUpdate
(
entity
);
}
/**
* 部门路径生成
*
* @param parentId 父ID
* @return 父节点路径以英文逗号(, )分割,eg: 1,2,3
*/
private
String
generateMenuTreePath
(
Long
parentId
)
{
if
(
SystemConstants
.
ROOT_NODE_ID
.
equals
(
parentId
))
{
return
String
.
valueOf
(
parentId
);
}
else
{
SysMenu
parent
=
this
.
getById
(
parentId
);
return
parent
!=
null
?
parent
.
getTreePath
()
+
","
+
parent
.
getId
()
:
null
;
}
}
...
...
@@ -208,59 +290,5 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
return
true
;
}
/**
* 递归生成菜单列表
*
* @param parentId 父级ID
* @param menuList 菜单列表
* @return
*/
private
List
<
MenuVO
>
recurMenus
(
Long
parentId
,
List
<
SysMenu
>
menuList
)
{
return
CollectionUtil
.
emptyIfNull
(
menuList
)
.
stream
()
.
filter
(
menu
->
menu
.
getParentId
().
equals
(
parentId
))
.
map
(
entity
->
{
MenuVO
menuVO
=
menuConverter
.
entity2Vo
(
entity
);
List
<
MenuVO
>
children
=
recurMenus
(
entity
.
getId
(),
menuList
);
menuVO
.
setChildren
(
children
);
return
menuVO
;
}).
toList
();
}
/**
* 递归生成菜单下拉层级列表
*
* @param parentId 父级ID
* @param menuList 菜单列表
* @return
*/
private
static
List
<
Option
>
recurMenuOptions
(
Long
parentId
,
List
<
SysMenu
>
menuList
)
{
List
<
Option
>
menus
=
CollectionUtil
.
emptyIfNull
(
menuList
).
stream
()
.
filter
(
menu
->
menu
.
getParentId
().
equals
(
parentId
))
.
map
(
menu
->
new
Option
(
menu
.
getId
(),
menu
.
getName
(),
recurMenuOptions
(
menu
.
getId
(),
menuList
)))
.
collect
(
ArrayList:
:
new
,
ArrayList:
:
add
,
ArrayList:
:
addAll
);
return
menus
;
}
/**
* 部门路径生成
*
* @param parentId 父ID
* @return 父节点路径以英文逗号(, )分割,eg: 1,2,3
*/
private
String
generateMenuTreePath
(
Long
parentId
)
{
String
treePath
=
null
;
if
(
SystemConstants
.
ROOT_NODE_ID
.
equals
(
parentId
))
{
treePath
=
String
.
valueOf
(
parentId
);
}
else
{
SysMenu
parent
=
this
.
getById
(
parentId
);
if
(
parent
!=
null
)
{
treePath
=
parent
.
getTreePath
()
+
","
+
parent
.
getId
();
}
}
return
treePath
;
}
}
youlai-system/system-boot/src/main/resources/mapper/SysMenuMapper.xml
浏览文件 @
9f30696a
...
...
@@ -11,7 +11,7 @@
<result
property=
"parentId"
column=
"parent_id"
jdbcType=
"BIGINT"
/>
<result
property=
"path"
column=
"path"
jdbcType=
"VARCHAR"
/>
<result
property=
"component"
column=
"component"
jdbcType=
"VARCHAR"
/>
<result
property=
"redirect
Url"
column=
"redirect_url
"
jdbcType=
"VARCHAR"
/>
<result
property=
"redirect
"
column=
"redirect
"
jdbcType=
"VARCHAR"
/>
<result
property=
"icon"
column=
"icon"
jdbcType=
"VARCHAR"
/>
<result
property=
"sort"
column=
"sort"
jdbcType=
"INTEGER"
/>
<result
property=
"visible"
column=
"visible"
jdbcType=
"BOOLEAN"
/>
...
...
@@ -32,9 +32,11 @@
t1.icon,
t1.sort,
t1.visible,
t1.redirect
_url
,
t1.redirect,
t1.type,
t3.code
t3.code,
t1.always_show,
t1.keep_alive
FROM
sys_menu t1
LEFT JOIN sys_role_menu t2 ON t1.id = t2.menu_id
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录