查询菜单的时候,我们可能会想直接从数据库中查询出菜单,但是像京东的首页菜单是这样的:
我们在设计数据库的时候仅仅使用一张表就可以把上面的关系给捋清楚,就是通过一个parentid字段,让我们开看一下这张表的表结构
看一下建表语句
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键递增',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分类名称',
`parentid` int(11) NULL DEFAULT NULL COMMENT '父节点id',
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分类链接',
`icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分类图标',
`order` int(11) NULL DEFAULT NULL COMMENT '分类排序权重',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
INSERT INTO `menu` VALUES (1, '新闻', 0, '/www/xinwen', 'xxx', 1);
INSERT INTO `menu` VALUES (2, '每日日报', 1, '/www/meiriribao', 'xxx', 2);
INSERT INTO `menu` VALUES (3, '每日晚报', 1, '/www/zaobao', 'xxx', 1);
INSERT INTO `menu` VALUES (4, '河南日报', 2, '/www/henan', 'xxx', 2);
INSERT INTO `menu` VALUES (5, '上海日报', 2, '/www/shanghai', 'xxx', 1);
INSERT INTO `menu` VALUES (6, '南京日报', 2, '/www/nanjing', 'xxx', 3);
INSERT INTO `menu` VALUES (7, '开封日报', 4, '/www/zhoukou', 'xxx', 2);
INSERT INTO `menu` VALUES (8, '郑州日报', 4, '/www/zhenghzou', 'xxx', 3);
实体类
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class Menu implements Comparable<Menu>, Serializable {
private static final long serialVersionUID = -4866555859812317355L;
private Integer id;
private String name;
private Integer parentId;
private String url;
private String icon;
private Integer order;
//子菜单列表
private List<Menu> children;
@Override
public int compareTo(Menu o) {
if(this.order != o.order){
return this.order - o.order;
}
return 0;
}
}
先看看controller层:
@Autowired
private MenuService menuService;
@RequestMapping(value = "/menu/findTree",method = RequestMethod.POST)
public BaseResponse create(@RequestBody(required = false) Menu menu) {
List<Menu> list = menuService.findAll(menu);
return BaseResponse.ok(list);
}
service接口
import com.free.freedom.entity.Menu;
import java.util.List;
public interface MenuService {
List<Menu> findAll(Menu menu);
}
实现类
import com.free.freedom.entity.Menu;
import com.free.freedom.mapper.MenuMapper;
import com.free.freedom.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Service
public class MenuServiceImpl implements MenuService {
@Autowired
private MenuMapper menuMapper;
@Override
public List<Menu> findAll(Menu menu) {
try {
//查询出所有的菜单
List<Menu> allMenu = menuMapper.findAll();
//根节点存储
List<Menu> rootMenu = new ArrayList<>();
//根据传递的参数设置根节点
if(menu != null && menu.getId()!= null){
//父节点为传递的id为根节点
for (Menu nav : allMenu) {
if(nav.getParentId().equals(menu.getId())){
rootMenu.add(nav);
}
}
}else {
//父节点是0的,为根节点
for (Menu nav : allMenu) {
if(nav.getParentId().equals(0)){
rootMenu.add(nav);
}
}
}
// 根据Menu类的order排序
Collections.sort(rootMenu);
//为根节点设置子菜单,getChild是递归调用
for (Menu nv : rootMenu) {
//获取根节点下的所有子节点,使用getChild方法
List<Menu> childList = getChild(nv.getId(),allMenu);
//给根节点设置子节点
nv.setChildren(childList);
}
return rootMenu;
} catch (Exception e) {
e.printStackTrace();
return new ArrayList<>();
}
}
private List<Menu> getChild(Integer id, List<Menu> allMenu) {
//子菜单
List<Menu> childList = new ArrayList<>();
for (Menu nav : allMenu) {
//遍历所有节点,将所有菜单的父id与传过来的根节点的id比较
//相等说明:为该根节点的子节点
if(nav.getParentId().equals(id)){
childList.add(nav);
}
}
//递归设置子节点
for (Menu nav : childList) {
nav.setChildren(getChild(nav.getId(),allMenu));
}
//排序
Collections.sort(childList);
//如果节点下没有子节点,返回一个空List(递归退出)
if(childList.size() == 0){
return new ArrayList<Menu>();
}
return childList;
}
}
mapper层
import com.free.freedom.entity.Menu;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface MenuMapper {
List<Menu> findAll();
}
mapper.xml
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.free.freedom.mapper.MenuMapper">
<resultMap id="BaseResultMap" type="com.free.freedom.entity.Menu">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="parentid" jdbcType="INTEGER" property="parentId" />
<result column="url" jdbcType="VARCHAR" property="url" />
<result column="icon" jdbcType="VARCHAR" property="icon" />
<result column="order" jdbcType="INTEGER" property="order" />
</resultMap>
<select id="findAll" resultMap="BaseResultMap">
select * from menu
</select>
</mapper>
{
"status": 0,
"msg": "OK",
"data": [
{
"id": 1,
"name": "新闻",
"parentId": 0,
"url": "/www/xinwen",
"icon": "xxx",
"order": 1,
"children": [
{
"id": 3,
"name": "每日晚报",
"parentId": 1,
"url": "/www/zaobao",
"icon": "xxx",
"order": 1,
"children": []
},
{
"id": 2,
"name": "每日日报",
"parentId": 1,
"url": "/www/meiriribao",
"icon": "xxx",
"order": 2,
"children": [
{
"id": 5,
"name": "上海日报",
"parentId": 2,
"url": "/www/shanghai",
"icon": "xxx",
"order": 1,
"children": []
},
{
"id": 4,
"name": "河南日报",
"parentId": 2,
"url": "/www/henan",
"icon": "xxx",
"order": 2,
"children": [
{
"id": 7,
"name": "开封日报",
"parentId": 4,
"url": "/www/zhoukou",
"icon": "xxx",
"order": 2,
"children": []
},
{
"id": 8,
"name": "郑州日报",
"parentId": 4,
"url": "/www/zhenghzou",
"icon": "xxx",
"order": 3,
"children": []
}
]
},
{
"id": 6,
"name": "南京日报",
"parentId": 2,
"url": "/www/nanjing",
"icon": "xxx",
"order": 3,
"children": []
}
]
}
]
},
{
"id": 9,
"name": "联播",
"parentId": 0,
"url": "/www/xinwen",
"icon": "xxx",
"order": 1,
"children": []
}
]
}
{
"status": 0,
"msg": "OK",
"data": [
{
"id": 5,
"name": "上海日报",
"parentId": 2,
"url": "/www/shanghai",
"icon": "xxx",
"order": 1,
"children": []
},
{
"id": 4,
"name": "河南日报",
"parentId": 2,
"url": "/www/henan",
"icon": "xxx",
"order": 2,
"children": [
{
"id": 7,
"name": "开封日报",
"parentId": 4,
"url": "/www/zhoukou",
"icon": "xxx",
"order": 2,
"children": []
},
{
"id": 8,
"name": "郑州日报",
"parentId": 4,
"url": "/www/zhenghzou",
"icon": "xxx",
"order": 3,
"children": []
}
]
},
{
"id": 6,
"name": "南京日报",
"parentId": 2,
"url": "/www/nanjing",
"icon": "xxx",
"order": 3,
"children": []
}
]
}