• java返回树形结构的正确姿势


    业务场景

    通常我们前端需要一个树形的导航菜单或者分类菜单,如后台权限管理中的权限树,亦或者下面例子中商城系统的商品分类多级菜单(一般为三级菜单)

    数据库设计

    数据库设计,采用parentId来指向自己的父级菜单,如:

    CREATE TABLE `pms_category` (
      `cat_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类id',
      `name` char(50) DEFAULT NULL COMMENT '分类名称',
      `parent_cid` bigint(20) DEFAULT NULL COMMENT '父分类id',
      `cat_level` int(11) DEFAULT NULL COMMENT '层级',
      `show_status` tinyint(4) DEFAULT NULL COMMENT '是否显示[0-不显示,1显示]',
      `sort` int(11) DEFAULT NULL COMMENT '排序',
      `icon` char(255) DEFAULT NULL COMMENT '图标地址',
      `product_unit` char(50) DEFAULT NULL COMMENT '计量单位',
      `product_count` int(11) DEFAULT NULL COMMENT '商品数量',
      PRIMARY KEY (`cat_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1433 DEFAULT CHARSET=utf8mb4 COMMENT='商品三级分类';
    

    java组装树形结构

    之前的做法是通过sql自连接来查出树形结构数据,但是效率不高,我们知道单表查询效率是最高的,我们可以一次查出所有数据,通过java8的新特性 stream来处理数据,stream是通过CPU计算实现,效率极高,具体用法可以参考:
    Java 8新特性之 Lambd和StreamAPI

    下面是处理数据的两个主要方法:

    @Override
    public List<CategoryEntity> listWithTree() {
        // 1. 先查出所有分类数据
        List<CategoryEntity> categories = baseMapper.selectList(null);
        // 2. 找出所有一级分类
        //    在映射到每个一级分类 添加它的子分类类
        return categories.stream()
                .filter(o -> o.getParentCid() == 0)
                // 给每个一级分类加子分类
                .peek(o -> o.setChildrens(getChildCategoryList(o, categories)))
                // 排序
                .sorted(Comparator.comparingInt(CategoryEntity::getSort))
                // 收集
                .collect(Collectors.toList());
    }
    
    // 根据当前分类 找出子类, 并通过递归找出子类的子类
    private List<CategoryEntity> getChildCategoryList(CategoryEntity currMenu, List<CategoryEntity> categories) {
        return categories.stream().filter(o -> o.getParentCid().equals(currMenu.getCatId()))
                .peek(o -> o.setChildrens(getChildCategoryList(o, categories)))
                .sorted(Comparator.comparingInt(CategoryEntity::getSort))
                .collect(Collectors.toList());
    }
    

    实体类变动

    • 为了拼接子菜单,需要将实体类增加一个属性childrens
    • 排序时需要用到sort属性,该字段在数据库可能为null,采用三元运算将其默认为0,防止排序异常
    @TableField(exist = false)
    private List<CategoryEntity> childrens;
    
    public Integer getSort() {
        return sort == null ? 0 : sort;
    }
    

    返回数据效果

  • 相关阅读:
    Android系统启动:1-综述
    在高通Fastmmi模式中增强交互方式
    Ubuntu 18.04安装xdrp以使用远程桌面
    如何在Android 确定 lunch对应的内核配置
    Android ADB命令集锦
    Android日志系统(logging system)
    汉诺塔游戏
    设置静态ip
    navicat的下载、激活
    上传本地文件到github(码云)上(小乌龟方式,sourcetree方式)
  • 原文地址:https://www.cnblogs.com/chengming104/p/13612550.html
Copyright © 2020-2023  润新知