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;
}

返回數據效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM