两种方式,前端直接读取已有的json文件或者请求后端来动态生成json数据。
首先把js贴上。
//dynamicMenu.js 主要的js文件
;(function($) {
var SidebarMenu = function($element, options) {
this.$element = $element;
this.options = $.extend({}, $.fn.sidebarMenu.defaults, options);
this.init();
};
SidebarMenu.prototype.init = function() {
var $element = this.$element;
var options = this.options;
var initMenu = this.initMenu;
if (options.data) {
initMenu($element, options.data);
} else {
if (!options.url)
return;
$.getJSON(options.url, options.param, function(data2) {
initMenu($element, data2);
});
}
};
SidebarMenu.prototype.initMenu = function(target, data) {
$.each(data, function() {
var $li = $("<li class='layui-nav-item layui-bg-cyan'></li>");
var $a = $("<a href='javascript:;'></a>").text(this.a.title);
var $dl = $("<dl class='layui-nav-child'></dl>");
$li.append($a);
$li.append($dl);
target.append($li);
menu($a, this.dl, $dl);
});
};
SidebarMenu.prototype.menu = function($a, dl, $dl) {
var ddArrObj = dl.dd;
$.each(ddArrObj, function() {
var $a_ = $("<a></a>", this.a).text(this.a.title);
var $dl_ = $("<dl class='layui-nav-child'></dl>");
var $dd_ = $("<dd></dd>");
$dd_.append($a_);
$dl.append($dd_);
if (this.a.leaf)
return true;
$a_.attr("href", "javascript:;");
$dd_.append($dl_);
menu($a_, this.dl, $dl_);
});
};
var menu = SidebarMenu.prototype.menu;
$.fn.sidebarMenu = function(options) {
return this.each(function() {
new SidebarMenu($(this),options);
});
};
$.fn.sidebarMenu.defaults = {
url: null,
param: null,
data: null
};
}
)(jQuery);
调用:
//desktop.js 显示菜单
$(function() {
$('ul#side-menu').sidebarMenu({
data:ssh_menu_routes //这种形式是前端直接读取已有的json文件
//url: '/ssh/base/person-jsonMenu' //这种形式是请求后端来动态生成json数据,使用一种方式即可
});
});
前端已有的json文件:
var ssh_menu_routes = [{
"a": {
"leaf": false,
"title": "系统管理",
"id": 100,
},
"dl": {
"dl-id": "xx",
"dd": [{
"a": {
"leaf": true,
"title": "主页展示",
"id": 1001,
"href": "#",
"data-id": 1001,
"data-url": "/ssh/templates/home.html",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "账号信息",
"id": 1002,
"href": "#",
"data-id": 1002,
"data-url": "/ssh/base/person-account",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "我的博客",
"id": 1003,
"href": "#",
"data-id": 1003,
"data-url": "/ssh/base/blog-query",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "实时聊天",
"id": 1004,
"href": "#",
"data-id": 1004,
"data-url": "/ssh/templates/chat.jsp",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "数据监控",
"id": 1005,
"href": "#",
"data-id": 1005,
"data-url": "/ssh/druid/index.html",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "EasyUI",
"id": 1006,
"href": "#",
"data-id": 1006,
"data-url": "/ssh/easyui/easyui-view",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "jquery验证",
"id": 1007,
"href": "#",
"data-id": 1007,
"data-url": "/ssh/jqueryvalidation/validation-view",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "jquery验证2",
"id": 1008,
"href": "#",
"data-id": 1008,
"data-url": "/ssh/jqueryvalidation/validation-view2",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": false,
"title": "Layui",
"id": 1009,
},
"dl": {
"dl-id": "xx",
"dd": [{
"a": {
"leaf": true,
"title": "Layui学习",
"id": 10001,
"href": "#",
"data-id": 10001,
"data-url": "/ssh/layui/layui-view",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "主页展示2",
"id": 10002,
"href": "#",
"data-id": 10002,
"data-url": "/ssh/templates/home.html",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": false,
"title": "主页展示3",
"id": 10003,
},
"dl": {
"dl-id": "xx",
"dd": [{
"a": {
"leaf": true,
"title": "主页展示11",
"id": 100001,
"href": "#",
"data-id": 100001,
"data-url": "/ssh/templates/home.html",
"class": "site-demo-active",
}
}, {
"a": {
"leaf": true,
"title": "主页展示22",
"id": 100002,
"href": "#",
"data-id": 100002,
"data-url": "/ssh/templates/home.html",
"class": "site-demo-active",
}
}, ],
}
}, ],
}
}, ],
}
}, {
"a": {
"leaf": false,
"title": "业务管理",
"id": 200,
},
"dl": {
"dl-id": "xx",
"dd": [{
"a": {
"leaf": true,
"title": "主页展示1",
"id": 2001,
"href": "#",
"data-id": 2001,
"data-url": "/ssh/templates/home.html",
"class": "site-demo-active",
}
}],
}
}, {
"a": {
"leaf": false,
"title": "报表统计",
"id": 300,
},
"dl": {
"dl-id": "xx",
"dd": [{
"a": {
"leaf": true,
"title": "主页展示2",
"id": 3001,
"href": "#",
"data-id": 3001,
"data-url": "/ssh/templates/home.html",
"class": "site-demo-active",
}
}],
}
}, ];
后端生成json使用java代码实现:
菜单实体类:
package com.nfl.base.domain;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.utils.BaseDomain;
@Entity
@Table(name = "SSH_MENU")
public class Menu extends BaseDomain {
private static final long serialVersionUID = -578218727059597787L;
private String title;
private String href;
private Long parentId;
private Long dataId;
private String dataUrl;
private List<Menu> subMenus;
public void addSubMenus(Menu menu) {
if (subMenus == null) {
subMenus = new ArrayList<Menu>();
}
subMenus.add(menu);
}
@Transient
public List<Menu> getSubMenus() {
return subMenus;
}
@Column(name = "TITLE")
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Column(name = "HREF")
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
@Column(name = "PARENT_ID")
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
@Column(name = "DATA_ID")
public Long getDataId() {
return dataId;
}
public void setDataId(Long dataId) {
this.dataId = dataId;
}
@Column(name = "DATA_URL")
public String getDataUrl() {
return dataUrl;
}
public void setDataUrl(String dataUrl) {
this.dataUrl = dataUrl;
}
}
上面的BaseDomain是一个生成主键的父类,使用mysql时可以直接把主键定义成自增的形式。
package com.utils;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.hibernate.annotations.GenericGenerator;
@MappedSuperclass
public abstract class BaseDomain implements Serializable {
private static final long serialVersionUID = 88655228488163320L;
private Long id;
@Id
@GeneratedValue(generator = "MyGenerator")
@GenericGenerator(name = "MyGenerator", strategy = "com.utils.MyIdGenerator")
@Column(name = "ID")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
获取所有菜单:
package com.nfl.base.manager;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.nfl.base.domain.Menu;
@Service("menuManager")
public class MenuManager extends AbstractDao<Menu> {
public Map<Long, Menu> getAllMenu() {
String hql = "from Menu m order by m.parentId asc,m.id asc";
List<Menu> menus = this.baseDao.find(null, hql, false);
Map<Long, Menu> map = new LinkedHashMap<>();
for (Menu m : menus) {
map.put(m.getId(), m);
Menu parentMenu = map.get(m.getParentId());
if (parentMenu != null) {
parentMenu.addSubMenus(m);
}
}
return map;
}
}
生成json数据,放到session:
package com.filter;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import com.nfl.base.domain.Menu;
import com.nfl.base.domain.Person;
import com.nfl.base.manager.MenuManager;
import com.nfl.base.manager.PersonManager;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
@Autowired
private PersonManager personManager;
@Autowired
private MenuManager menuManager;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
String username = request.getParameter("username");
List<Person> personList = personManager.find(null, "from Person p where p.username=?0 order by id asc", false,
username);
Person person = personList.get(0);
HttpSession session = request.getSession();
session.setAttribute("activeUser", person);
processMenu(session);
response.sendRedirect(request.getContextPath() + "/base/person-desktop");
}
/**
* 整理菜单
*/
private void processMenu(HttpSession session) {
Map<Long, Menu> allMenu = menuManager.getAllMenu();
List<Menu> subMenus = allMenu.get(0L).getSubMenus();
JSONArray jArr = new JSONArray();
for (Menu subMenu : subMenus) {
JSONObject jo = new JSONObject();
if (subMenu.getSubMenus() == null || subMenu.getSubMenus().size() == 0) {
continue;
}
recurrenceMenu(jo, subMenu);
jArr.add(jo);
}
session.setAttribute("allMenus", jArr);
}
/**
* 递归处理菜单,将菜单对象包装成JSONObject对象
*/
private void recurrenceMenu(JSONObject jo, Menu menu) {
JSONObject aJo = new JSONObject();
aJo.put("title", menu.getTitle());
aJo.put("id", menu.getId());
// 没有子菜单意味着当前菜单可表示为一片叶子
if (menu.getSubMenus() == null || menu.getSubMenus().size() == 0) {
aJo.put("leaf", Boolean.TRUE);
aJo.put("href", "#");
aJo.put("data-id", menu.getId());
aJo.put("data-url", menu.getDataUrl());
jo.put("a", aJo);
} else {
aJo.put("leaf", Boolean.FALSE);
List<Menu> subMenus = menu.getSubMenus();
JSONObject dlJo = new JSONObject();
dlJo.put("dl-id", "xx");
JSONArray ddjArr = new JSONArray();
for (Menu mm : subMenus) {
JSONObject _aJo = new JSONObject();
recurrenceMenu(_aJo, mm);
ddjArr.add(_aJo);
}
dlJo.put("dd", ddjArr);
jo.put("a", aJo);
jo.put("dl", dlJo);
}
}
}
请求获取菜单的json数据:
package com.nfl.base.web;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import com.nfl.base.domain.Person;
import com.utils.EntityAction;
@Namespace("/base")
@ParentPackage("basePackage")
public class PersonAction extends EntityAction<Person> {
private static final long serialVersionUID = 8765563996036355208L;
public void jsonMenu() {
rendJson(getSessionAttr("allMenus"));
}
}
实际上就是一个简单的递归,当前菜单是叶子时代表到底了,不会继续递归。
最后是首页的html:
<!DOCTYPE HTML>
<html>
<head>
<title>(▼へ▼メ)</title>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="https://www.layuicdn.com/layui-v2.5.4/css/layui.css">
<style>.layui-tab-content {padding: 0;}</style>
<style>.layui-layout-admin .layui-body {top: 50px;}</style>
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<div class="layui-header layui-bg-cyan">
<div class="layui-logo"><a href=""><i class="layui-icon layui-icon-home" style="color: #1E9FFF;"></i></a></div>
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item"><i title="侧边伸缩" class="layui-icon layui-icon-shrink-right" id="left_open" style="cursor:pointer;"></i></li>
<li class="layui-nav-item"><a href="">用户<span class="layui-badge">9</span></a></li>
<li class="layui-nav-item"><a href="">角色<span class="layui-badge-dot"></span></a></li>
<li class="layui-nav-item"><a href="">权限</a></li>
<li class="layui-nav-item">
<a href="javascript:;">其它系统</a>
<dl class="layui-nav-child layui-anim layui-anim-upbit">
<dd><a href="">邮件管理</a></dd>
<dd><a href="">消息管理</a></dd>
<dd><a href="">授权管理</a></dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">
<img src="${contextPath}/images/initpic.jpg" class="layui-nav-img"><b><i>${activeUser.username}</i></b>
</a>
<dl class="layui-nav-child">
<dd><a href="#" id="001" data-url="${contextPath}/systemPages/personal/personalData.jsp" data-id="001" class="">基本资料</a></dd>
<dd><a href="#" id="002" data-id="002" class="site-demo-active">修改密码</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a href="${contextPath}/logout">退出</a></li>
</ul>
</div>
<div class="layui-side layui-bg-cyan">
<div class="layui-side-scroll">
<ul class="layui-nav layui-nav-tree" lay-shrink="all" id="side-menu"></ul>
</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
<div class="layui-tab layui-tab-brief" lay-filter="tabBar" lay-allowClose="true">
<ul class="layui-tab-title"></ul>
<ul class="rightmenu" style="display: none;position: absolute;">
<li data-type="closethis"><a href="javascript:;" class="layui-btn">关闭当前</a></li>
<li data-type="closeother"><a href="javascript:;" class="layui-btn">关闭其他</a></li>
</ul>
<div class="layui-tab-content"></div>
</div>
</div>
<div class="layui-footer">页底区域</div>
</div>
<script src="https://cdn.bootcss.com/jquery/1.7.2/jquery.min.js"></script>
<script src="https://www.layuicdn.com/layui-v2.5.4/layui.js"></script>
<script src="${contextPath}/js/tabs.js"></script>
<script src="${contextPath}/js/dynamicMenu.js"></script>
<script src="${contextPath}/js/desktop.js"></script>
</body>
</html>