表结构
CREATE TABLE `menu` (
`menu_id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(11) DEFAULT NULL,
`name` varchar(50) DEFAULT NULL,
`icon` varchar(20) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
`sort` int(11) NULL DEFAULT NULL,
`remark` varchar(255) DEFAULT NULL,
`state` varchar(10) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
造些数据
INSERT INTO `menu` VALUES (1, NULL, '系统管理', '', NULL, 1, NULL, 'A', now(), now());
INSERT INTO `menu` VALUES (2, 1, '菜单管理', '', NULL, 1, NULL, 'A', now(), now());
INSERT INTO `menu` VALUES (3, 2, '新增菜单', '', NULL, NULL, NULL, 'A', now(), now());
INSERT INTO `menu` VALUES (4, NULL, '账户管理', '', NULL, 2, NULL, 'A', now(), now());
INSERT INTO `menu` VALUES (5, 1, '权限管理', '', NULL, 2, NULL, 'A', now(), now());
INSERT INTO `menu` VALUES (6, 4, '账户列表', '', NULL, NULL, NULL, 'A', now(), now());
INSERT INTO `menu` VALUES (7, 3, '新菜单', '', NULL, NULL, NULL, 'A', now(), now());
INSERT INTO `menu` VALUES (8, 7, '新菜单1', NULL, NULL, NULL, NULL, 'A', now(), now());
后台接口
Action
@RestController
@RequestMapping(value = "menu")
@Slf4j
public class MenuAction {
@Autowired
private MenuService menuService;
@RequestMapping(value = "getMenu", method = RequestMethod.GET)
public Result getMenuJson() {
Result result = new MapResult();
try {
result = menuService.getMenuJson(null);
}catch (Exception e){
log.error("MenuAction.getMenu:"+e.getMessage());
}
return result;
}
}
serviceImpl
@Override
public Result getMenuJson(Integer userId) {
Result result = new MapResult();
try {
JSONObject menuJson = new JSONObject();
getAllChildrenMenuByPid(menuJson);
result.defaultSuccess();
result.setData("menuJson", menuJson);
} catch (Exception e) {
Logger.exception(e.getMessage(), e);
result.setMessage(e.getMessage());
}
return result;
}
/**
* 递归查询 节点下子节点
*/
private void getAllChildrenMenuByPid(JSONObject pJson) {
Integer pid = pJson.getInteger("menuId");
List<Menu> childrenMenus = menuMapper.getMenuByPid(pid);
if (childrenMenus==null||childrenMenus.isEmpty()) return;
JSONArray children = new JSONArray();
for (Menu child : childrenMenus) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("pid",child.getPid());
jsonObject.put("name",child.getName());
jsonObject.put("menuId",child.getMenuId());
jsonObject.put("icon",child.getIcon());
jsonObject.put("url",child.getUrl());
children.add(jsonObject);
//递归查询
getAllChildrenMenuByPid(jsonObject);
}
pJson.put("children",children);
}
dao
List<Menu> getMenuByPid(@Param("pid") Integer pid);
Mapper.xml
<!-- 根据父级查询 -->
<select id="getMenuByPid" resultMap="MenuMap">
select * from menu
where
state!='X'
<if test="pid==null or pid=='' ">
and pid is null or pid =''
</if>
<if test="pid!=null and pid!='' ">
and pid = #{pid}
</if>
order by `sort` desc
</select>
pojo
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* @author
*
*/
@Data
@EqualsAndHashCode
@ToString
public class Menu implements Pojo {
private static final long serialVersionUID = -1L;
//columns START
/** menuId */
private java.lang.Integer menuId;
/** pid */
private java.lang.Integer pid;
/** name */
private java.lang.String name;
/** icon */
private java.lang.String icon;
/** sort */
private java.lang.Integer sort;
/** url */
private java.lang.String url;
/** remark */
private java.lang.String remark;
/** state */
private java.lang.String state;
/** createTime */
private java.util.Date createTime;
/** updateTime */
private java.util.Date updateTime;
//columns END
}
前端代码
html
<!-- 左侧菜单开始 -->
<div class="left-nav">
<div id="side-nav">
<ul id="nav">
</ul>
</div>
</div>
<!-- 左侧菜单结束 -->
js
$(function () {
initMenu()
});
/**
* 加载菜单
*/
function initMenu() {
$.ajax({
url: '/menu/getMenu',
dataType: 'json',
success: function (result) {
var menuJson = result.datas.menuJson.children;
if (menuJson) {
var $html = $('#nav');
getMenuHtml($html, menuJson, 0)
}
console.log(menuJson);
}
});
}
/**
* 获取菜单html
* @param $html 需要填充的dom
* @param menu_list 数据
* @param num 菜单级别
*/
function getMenuHtml($html, menu_list, num) {
num++;
for (var i in menu_list) {
var menu = menu_list[i];
var pid = menu['pid'];
var menuId = menu['menuId'];
var name = menu['name'];
var icon = menu['icon'];
var url = menu['url'];
var children = menu['children'];
if (pid === null || pid === '') {
var html_new_ =
'<li id="' + menuId + '">' +
'<a style="padding-left: '+10*num+'px;" href="javascript:;">' +
'<i class="layui-icon left-nav-li" lay-tips="' + name + '">' + (icon ? icon : '') + '</i>' +
'<cite>' + name + '</cite>' +
'<i class="iconfont nav_right"></i></a>' +
'<ul class="sub-menu" id="menu_ul_' + menuId + '">' +
'</ul>' +
'</li>';
$html.append(html_new_);
} else {
var html;
if (children && children.length > 0) {
html =
'<li id="' + menuId + '">' +
'<a style="padding-left: '+10*num+'px;" href="javascript:;">' +
'<i class="layui-icon left-nav-li" lay-tips="' + name + '">' + (icon ? icon : '') + '</i>' +
'<cite>' + name + '</cite>' +
'<i class="iconfont nav_right"></i></a>' +
'<ul class="sub-menu" id="menu_ul_' + menuId + '">' +
'</ul>' +
'</li>';
$("#menu_ul_" + pid).append(html);
} else {
html = ' <li>' +
' <a style="padding-left: '+10*num+'px;" οnclick="xadmin.add_tab(\'' + name + '\',\'' + url + '\')">' +
' <i class="layui-icon">'+ (icon ? icon : '') + '</i>' +
' <cite>' + name + '</cite></a>' +
'<ul id="menu_ul_' + menuId + '">' +
'</ul>' +
' </li>';
$("#menu_ul_" + pid).append(html);
}
}
if (children && children.length > 0) {
getMenuHtml($html, children,num);
}
}
}
效果
总结
造了五级数据,速度有点慢,应该能优化
异步菜单会后展示1s,同步整个页面加载慢一点
测试几次 基本在800ms 到 1s 之间,有缓存在80~150ms
方案一:
减少查询次数,一次查出数据,然后在内存构造数据结构
方案二:
改变数据结构,能否用有序集合解决。