采纳答案成功!
向帮助你的同学说点啥吧!感谢那些助人为乐的人
权限菜单格式有点复杂
你好,动态处理菜单的代码写好了。现在具体说一下:
1、前提要求及设定:
1)由于目前项目使用的模板最多适合展示两层,因此我们这里要求配置权限模块时最多两级(尽管代码里是支持无限层级的,代码那样实现是为了支撑特别复杂的情形,并且容易扩展)
2)要求每个模块下最多设置一个菜单权限点,相当于映射到菜单时,代表菜单每一项点击时最多只有一个url被响应(如果配置多个,我们代码里只会选择第一项)
3)同一个菜单,如果有下级菜单,那么当前层级就不再配置菜单权限点了。同理,如果一个菜单配置了菜单权限点,就不再去关心他的下级菜单了,因为这个菜单被选择时,已经要做跳转操作了。这里主要是方便前端ui展示及配合ui模板处理,太复杂的情况另说。
2、接下来说下后端代码,
SysUserController.java下包装一个查询菜单接口:
@RequestMapping("/menu.json")
@ResponseBody
public JsonData menuTree() {
List<AclModuleLevelDto> aclModuleLevelDtoList = sysTreeService.userAclTree(RequestHolder.getCurrentUser().getId());
return JsonData.success(sysMenuService.changeTreeToMenu(aclModuleLevelDtoList));
}
userAclTree方法是现成的,适配成一个简单的menu结构返回
使用到的适配方法和类如下:
@Getter
@Setter
public class Menu {
private Integer id;
// 菜单展示的名称
private String name;
// 菜单点击跳转的链接
private String url;
// 下级菜单, 如果存在url里,就不存在下级菜单了
private List<Menu> subList = Lists.newArrayList();
public void addSubMenu(Menu menu) {
if (menu != null) {
subList.add(menu);
}
}
}
@Service
public class SysMenuService {
public List<Menu> changeTreeToMenu(List<AclModuleLevelDto> aclModuleLevelDtoList) {
List<Menu> menuList = Lists.newArrayList();
if (CollectionUtils.isEmpty(aclModuleLevelDtoList)) {
return menuList;
}
// 处理菜单
// 由于样式只适合最多两级,因此这里假设只有两层,尽管实现时层级是不限制多少级的
for (AclModuleLevelDto firstLevel : aclModuleLevelDtoList) {
Menu firstLevelMenu = new Menu();
firstLevelMenu.setId(firstLevel.getId());
firstLevelMenu.setName(firstLevel.getName());
boolean needAddFirstMenu = false; // 是否需要增加一级菜单
// 首先检查menu下是否已配置了有菜单的权限,如果有,就直接使用对应菜单的权限点的url作为点击后跳转的路径
if (CollectionUtils.isNotEmpty(firstLevel.getAclList())) {
for (AclDto aclDto : firstLevel.getAclList()) {
if (aclDto.getType() == 1 && StringUtils.isNotBlank(aclDto.getUrl())) { // 类型为菜单, 且配置了url
// 正常每个模块下应该只配置一个菜单的权限点,如果有多个,那是配置的有问题
firstLevelMenu.setUrl(aclDto.getUrl());
needAddFirstMenu = true;
break;
}
}
}
// 目前这个菜单还没有点击跳转的url, 而且下面还有子模块时,继续尝试处理下一层级
if(StringUtils.isBlank(firstLevelMenu.getUrl()) && CollectionUtils.isNotEmpty(firstLevel.getAclModuleList())) {
for (AclModuleLevelDto sendLevel : firstLevel.getAclModuleList()) {
Menu secondLevelMenu = new Menu();
secondLevelMenu.setId(sendLevel.getId());
secondLevelMenu.setName(sendLevel.getName());
boolean needAddSecondMenu = false; // 是否需要增加二级菜单
if (CollectionUtils.isNotEmpty(sendLevel.getAclList())) {
for (AclDto aclDto : sendLevel.getAclList()) {
if (aclDto.getType() == 1 && StringUtils.isNotBlank(aclDto.getUrl())) { // 类型为菜单, 且配置了url
// 正常每个模块下应该只配置一个菜单的权限点,如果有多个,那是配置的有问题
secondLevelMenu.setUrl(aclDto.getUrl());
needAddFirstMenu = true;
needAddSecondMenu = true;
break;
}
}
}
if (needAddSecondMenu) { // 需要增加二级菜单
firstLevelMenu.addSubMenu(secondLevelMenu);
}
}
}
if (needAddFirstMenu) { // 需要增加一级菜单
menuList.add(firstLevelMenu);
}
}
return menuList;
}
}
接口返回示例:
接下来,处理一下前端的渲染
涉及到菜单的渲染,只要调整admin.jsp就可以了
首先是增加菜单渲染的模板,这里包含三个主要是因为菜单分三种情况:
1)菜单只有一个层级,点击就进行页面跳转的,对应模板:urlMenuTemplate
2)菜单包含两个层级,第一层点击时打开第二层菜单,第二层点击时进行页面跳转。
第一层对应模板:emptyMenuTemplate
第二层对应模板:secondMenuTemplate
<script id="secondMenuTemplate" type="x-tmpl-mustache">
<b class="arrow"></b>
<ul class="submenu">
{{#subList}}
<li class="">
<a class="popstyle" href="{{url}}" target="_blank">
<i class="menu-icon fa fa-caret-right"></i>
{{name}}
</a>
<b class="arrow"></b>
</li>
{{/subList}}
</ul>
</script>
<script id="urlMenuTemplate" type="x-tmpl-mustache">
<a class="popstyle" href="{{url}}" target="_blank">
<i class="menu-icon fa fa-tachometer"></i>
{{name}}
</a>
<b class="arrow"></b>
</script>
<script id="emptyMenuTemplate" type="x-tmpl-mustache">
<a href="#" class="dropdown-toggle">
<i class="menu-icon fa fa-desktop"></i>
<span class="menu-text"> {{name}} </span>
<b class="arrow fa fa fa-caret-right"></b>
</a>
</script>
有了模板接下来就是修改页面的展示部分了
首先去掉页面上之前写死的菜单部分:
<ul class="nav nav-list">。。。(省略之前的菜单内容) </ul>
换成
<ul class="nav nav-list"></ul>
接下来是进行页面的实际渲染,admin.jsp页面最底下的的JavaScript替换成这段就可以了。
<script>
$(document).ready(function () {
$(function () {
var emptyMenuTemplate = $('#emptyMenuTemplate').html();
var urlMenuTemplate = $('#urlMenuTemplate').html();
var secondMenuTemplate = $('#secondMenuTemplate').html();
$.ajax({
url: "/sys/user/menu.json",
success : function (result) {
if(result.ret) {
var menuList = result.data;
$(menuList).each(function (i, firstMenu) {
if(firstMenu.url) { // 如果首层就有url的话
var appendFirst = Mustache.render(urlMenuTemplate, firstMenu);
$(".nav-list").append('<li class="">' + appendFirst + "</li>");
} else { // 如果是两层的话
var appendFirst = Mustache.render(emptyMenuTemplate, firstMenu);
var appendSend = Mustache.render(secondMenuTemplate, {
subList: firstMenu.subList
});
$(".nav-list").append('<li class="">' + appendFirst + appendSend + "</li>");
}
handleCommonBehavior();
});
} else {
showMessage("加载菜单", result.msg, false);
}
}
})
});
function handleCommonBehavior() {
$(".popstyle").removeAttr("target");
$(".popstyle").each(function () {
var $this = $(this);
tmp = $this.attr("href");
$this.attr("data", tmp);
$this.attr("href", "javascript:void(0)");
});
$(".popstyle").click(function () {
var $this = $(this);
$("iframe").attr(
'src',
$this.attr("data")
);
});
}
$(".direct").click(function () {
var $this = $(this);
$("iframe").attr(
'src',
$this.attr("data-value")
);
});
});
</script>
这样完成之后,在加载这个页面时,就会去后台请求实时的菜单数据,来进行动态渲染啦~
祝你学习愉快~
图标可以前端自己给个算法,这东西完全看实现者设计了,实在不行,可以给权限模块存储时加上一项图标
登录后可查看更多问答,登录/注册