菜单树的实现(SpringBoot + Vue)超详细!

菜单树的实现

菜单树类的实现,可以看这篇
新手小白,但超详细、超实用版!
有错误、有更好的思路、更好的实现方式请评论区留言更正,感谢!

1.构建数据库表

在这里插入图片描述

  • 构建数据库表的语句:
CREATE TABLE `menu` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '菜单id',
  `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '菜单图标',
  `menu_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '菜单名称',
  `has_third` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '(可以不用)',
  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '菜单路由',
  `pid` bigint DEFAULT NULL COMMENT '父菜单id',
  `order_value` int DEFAULT NULL COMMENT '菜单排序',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=177 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
  • 数据:
    在这里插入图片描述

这里要明白pid和order_value数据是怎么写的
pid就是该菜单的父菜单,没有就填0
order_value对每级菜单进行排序,对菜单的子菜单也进行排序

数据如下:
“1” “li-icon-xiangmuguanli” “基础管理” “0” “1”
“2” “icon-cat-skuQuery” “商品管理” “N” “goods/Goods” “1” “1”
“33” “li-icon-dingdanguanli” “订单管理” “0” “2”
“34” “icon-order-manage” “交易订单” “N” “pay/Order” “33” “1”
“71” “li-icon-xitongguanli” “系统管理” “0” “3”
“72” “icon-cus-manage” “用户管理” “N” “system/user” “71” “1”
“73” “icon-news-manage” “角色管理” “N” “system/Role” “71” “3”
“74” “icon-cs-manage” “公司管理” “N” “system/Dept” “71” “4”
“75” “icon-promotion-manage” “系统环境变量” “N” “system/Variable” “71” “5”
“76” “icon-cms-manage” “权限管理” “N” “system/Permission” “71” “6”
“128” “li-icon-shangchengxitongtubiaozitihuayuanwenjian91” “支付管理” “0” “5”
“129” “icon-provider-manage” “支付配置信息” “N” “machine/MachineConfig” “128” “1”
“150” “li-icon-shangchengxitongtubiaozitihuayuanwenjian91” “图表” “0” “4”
“159” “icon-provider-manage” “数据可视化” “N” “charts/statistics” “150” “1”
“174” “icon-cms-manage” “菜单管理” “N” “system/Module” “71” “2”
“175” “icon-provider-manage” “支付配置” “N” “pay/Config” “128” “2”

  • 最终菜单呈现:
    在这里插入图片描述

2.创建实体类对象

  • Menu实体类对象
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import lombok.Data;

@ApiModel(value = "Menu对象")
@Data
public class Menu implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    @JsonProperty("menuid")
    private Long id;
    private String icon;
    @JsonProperty("menuname")
    private String menuName;
    private String hasThird;
    private String url;
    private Long pid;
    private Integer orderValue;

}

  • MenuVO对象(返回给前端的对象)
import cn.lhn.entity.Menu;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;

@Data
public class MenuVO extends Menu {

    @JsonProperty("menus")
    private List<MenuVO> children;
}

当前端需要的字段和实体类属性不一致时,使用该注解
@JsonProperty(“menuname”):该注解的值对应于前端需要返回的字段名称
这个注解会把menuName映射成menuname
反正就那意思

3.构建菜单工具类

import cn.lhn.vo.MenuVO;
import java.util.ArrayList;
import java.util.List;

public class MenuTreeUtil {
	/**
     * 将传来的数据整理成Tree形数据
     * @param menuList 传来的数据(将要整理的数据)
     * @return menuTree 整理完成的数据
     */
    public static List<MenuVO> buildMenuTree(List<MenuVO> menuList){
        //定义要返回的、要构建的最终的菜单树
        List<MenuVO> menuTree = new ArrayList<>();
        for (MenuVO menu : menuList) {
            if (menu.getPid().longValue() == 0){    //找到根菜单
                menuTree.add(findChildren(menu,menuList));   //再寻找并添加子节点
            }
        }
        return menuTree;
    }
	/**
     * 在menuList数据中继续给menu找子菜单
     * @param menu 要追加子菜单的菜单
     * @param menuList 要查找的目标数据
     * @return 返回追加好的MenuVO
     */
    public static MenuVO findChildren(MenuVO menu,List<MenuVO> menuList){
        for (MenuVO item : menuList) {		//遍历要查找的数据
            if (menu.getId().longValue() == item.getPid().longValue()){	 //找到了子菜单
                if (menu.getChildren() == null){		//给要追加子菜单的菜单添加数组,准备添加子菜单
                    menu.setChildren(new ArrayList<MenuVO>());
                }
                menu.getChildren().add(findChildren(item,menuList)); 	//添加子菜单
            }
        }
        return menu;
    }
}

4.Controller层

import cn.lhn.result.Result;
import cn.lhn.service.IMenuService;
import cn.lhn.vo.MenuVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@Api(tags = "菜单模块")
@RestController
@RequestMapping
public class MenuController {

    @Autowired
    IMenuService menuService;
    
    @ApiOperation("获取菜单列表")
    @PostMapping("/Module/list")
    public Result<List<MenuVO>> menuList(){
        List<MenuVO> menuList = menuService.menu();
        return Result.ok(menuList);
    }
}

5.Service层

import cn.lhn.vo.MenuVO;
import java.util.List;

public interface IMenuService{
    List<MenuVO> menu();
}

import cn.lhn.entity.Menu;
import cn.lhn.mapper.MenuMapper;
import cn.lhn.service.IMenuService;
import cn.lhn.utils.JsonUtil;
import cn.lhn.utils.MenuTreeUtil;
import cn.lhn.vo.MenuVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class MenuServiceImpl implements IMenuService {

    @Autowired
    MenuMapper menuMapper;

    @Override
    public List<MenuVO> menu() {
    	//数据库查询数据
        List<MenuVO> menus = menuMapper.selectAll();
        //构建菜单树
        List<MenuVO> menuList = MenuTreeUtil.buildMenuTree(menus);
        //对菜单树根菜单进行排序
        menuList = menuList.stream().sorted(Comparator.comparing(Menu::getOrderValue))
                                .collect(Collectors.toList());
        return menuList;
    }
}

其实ServiceImpl和工具类就是实现菜单树的主要内容,还有实体类的构建

6.Mapper层

import cn.lhn.entity.Menu;
import cn.lhn.vo.MenuVO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface MenuMapper extends BaseMapper<Menu> {
	@Select("select * from menu")
    List<MenuVO> selectAll();
}

7.前端部分(仅供参考)

  • 前端的部分代码(仅供参考,看懂就行,前端不归我管!)
<el-tree class="treeclass" ref="tree" :data="treeData" 
			default-expand-all="" :props="defaultProps"
          	@node-click="nodeclick" @check-change="handleClick" 
          	check-strictly node-key="id" show-checkbox>
</el-tree>

:props=“defaultProps” :后端返回来的数据中的相应字段,要与defaultProps中的字段相对应
定义的实体类与前端需要的字段不一致时,可以使用前面说的@JsonProperty(“menus”)注解

export default {
  data() {
    return {
    	treeData: [],
    	defaultProps: {
	        children: 'menus',
	        label: 'menuname'
      	},
    }
  }
}
methods: {
    // 获取数据
    getdata() {
      ModuleList()
        .then(res => {
          this.treeData = res.data
        })
        .catch(err => {
          this.loading = false
          this.$message.error('菜单管理列表失败,请稍后再试!')
        })
    }
}
export const ModuleList = () => { return req("post", "/api/Module/list") };
  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java程序员十六

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值