java構(gòu)建樹形結(jié)構(gòu)的實現(xiàn)過程
更新時間:2025年11月10日 09:11:13 作者:xingweI2021
文章介紹了五種構(gòu)建樹形結(jié)構(gòu)的方式,包括定義實體類、利用Map集合、使用Stream流、基于Hutool以及MyBatis-Plus的@TableName屬性,最后,還提供了一個基于Java實現(xiàn)樹結(jié)構(gòu)模糊搜索功能的示例
構(gòu)建樹形結(jié)構(gòu)
廢話少說,直接上代碼
方式一
1、定義實體類
public class Category {
private Long id;
private String name;
private Long parentId;
private List<Category> children;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public List<Category> getChildren() {
return children;
}
public void setChildren(List<Category> children) {
this.children = children;
}
public Category(Long id, String name, Long parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
}
工具類
private static List<Category> categories = new ArrayList<>();
static {
// 綁定初始化一個Category的數(shù)據(jù)
categories.add(new Category(1L, "一級分類-1", null));
categories.add(new Category(2L, "一級分類-1-1", 1L));
categories.add(new Category(3L, "一級分類-1-2", 1L));
categories.add(new Category(30L, "一級分類-1-2-1", 3L));
categories.add(new Category(4L, "一級分類-2", null));
categories.add(new Category(5L, "一級分類-2-1", 4L));
categories.add(new Category(6L, "一級分類-3", null));
categories.add(new Category(7L, "一級分類-3-1", 6L));
// 子節(jié)點
}
public static void main(String[] args) {
String treeJson = JSONUtil.toJsonPrettyStr(parentList01());
System.out.println(treeJson);
}
private static List<Category> parentList01(){
List<Category> parentList = categories.stream().filter(category -> category.getParentId() == null).collect(Collectors.toList());
for (Category category : parentList) {
category.setChildren(buildChildren(category.getId(),categories));
}
return parentList;
}
private static List<Category> buildChildren(Long id, List<Category> categories) {
List<Category> children = new ArrayList<>();
for (Category category : categories) {
if (category.getParentId() == null){
continue;
}
if (category.getParentId().equals(id)){
children.add(category);
}
}
for (Category child : children) {
child.setChildren(buildChildren(child.getId(),categories));
}
return children;
}
方式二
利用Map集合
@Override
public Result currentLeftMenu() {
// 獲取認證主體
Subject subject = SecurityUtils.getSubject();
ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
Integer userId = activeUser.getSysUser().getId();
// 根據(jù)用戶ID 和 菜單權(quán)限查詢 權(quán)限
List<SysPermissionVO> sysPermissionVOS = sysPermissionMapper.selectUserPermission(userId, Constant.PERMISSION_TYPE_MENU);
// 菜單容器
Map<Integer, SysPermissionVO> menu = new HashMap<>();
for (SysPermissionVO sysPermissionVO : sysPermissionVOS) {
// 獲取菜單中的父ID
Integer parentId = sysPermissionVO.getParentId();
// 判斷父ID是否是一級菜單
if (parentId.equals(Constant.MENU_LV1)) {
sysPermissionVO.setChildren(new ArrayList<SysPermissionVO>());
// key 菜單的ID value
menu.put(sysPermissionVO.getId(), sysPermissionVO);
}
}
// 給1一級菜單賦二級菜單
for (SysPermissionVO sysPermissionVO : sysPermissionVOS) {
Integer parentId = sysPermissionVO.getParentId();
if (menu.containsKey(parentId)) {
SysPermissionVO sysPermissionVO1 = menu.get(parentId);
sysPermissionVO1.getChildren().add(sysPermissionVO);
}
}
Collection<SysPermissionVO> values = menu.values();
// 返回給controller
return new Result(values);
}
方式三:stream流方式
public List<CategoryEntity> listWithTree() {
//1、查出所有分類
List<CategoryEntity> entities = baseMapper.selectList(null);
//2、組裝成父子的樹形結(jié)構(gòu)
//2.1)、找到所有的一級分類,給children設(shè)置子分類
return entities.stream()
// 過濾找出一級分類
.filter(categoryEntity -> categoryEntity.getParentCid() == 0)
// 處理,給一級菜單遞歸設(shè)置子菜單
.peek(menu -> menu.setChildren(getChildless(menu, entities)))
// 按sort屬性排序
.sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort())))
.collect(Collectors.toList());
}
/**
* 遞歸查找所有菜單的子菜單
*/
private List<CategoryEntity> getChildless(CategoryEntity root, List<CategoryEntity> all) {
return all.stream()
.filter(categoryEntity -> categoryEntity.getParentCid().equals(root.getCatId()))
.peek(categoryEntity -> {
// 找到子菜單
categoryEntity.setChildren(getChildless(categoryEntity, all));
})
.sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort())))
.collect(Collectors.toList());
}
另一個
public List<CategoryEntity> listWithLambda() {
List<CategoryEntity> categorys = baseMapper.selectList(Wrappers.<CategoryEntity>lambdaQuery().orderByDesc(CategoryEntity::getCatId))
List<CategoryEntity> entities = new ArrayList<>(categorys);
Map<Long, List<CategoryEntity>> longListNavigableMap = entities.stream().collect(Collectors.groupingBy(CategoryEntity::getParentCid));
List<CategoryEntity> res = entities.stream().peek(entity -> {
if (longListNavigableMap.containsKey(entity.getCatId())) {
entity.setChildren(longListNavigableMap.get(entity.getCatId()));
}
}).filter(entity -> entity.getCatLevel() == 1).sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort()))).collect(Collectors.toList());
return res;
}
方式四:基于Hutool進行構(gòu)建
導(dǎo)入hutool的依賴,請參考hutool官網(wǎng)
實體類
@Data
@TableName("pms_category")
@AllArgsConstructor
public class CategoryEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 分類id
*/
@TableId
private Long catId;
/**
* 分類名稱
*/
private String name;
/**
* 父分類id
*/
private Long parentCid;
/**
* 層級
*/
private Integer catLevel;
/**
* 是否顯示[0-不顯示,1顯示]
*/
@TableLogic(value = "1",delval = "0")
private Integer showStatus;
/**
* 排序
*/
private Integer sort;
/**
* 圖標(biāo)地址
*/
private String icon;
/**
* 計量單位
*/
private String productUnit;
/**
* 商品數(shù)量
*/
private Integer productCount;
/**
* 所有子分類
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@TableField(exist = false)
private List<CategoryEntity> children;
}
service
public class TreeUtils{
public List<Tree<Long>> listWithTree() {
ArrayList<CategoryEntity> dataList = Lists.newArrayList();
dataList.add(new CategoryEntity(1L,"電子產(chǎn)品",0L,1,1,0,"/images/electronics.png","件",50,null));
dataList.add(new CategoryEntity(2L,"手機通訊",1L,2,1,0,"/images/electronics.png","件",150,null));
dataList.add(new CategoryEntity(3L,"家用電器",1L,2,1,0,"/images/electronics.png","件",250,null));
List<CategoryEntity> entities = dataList;
if (!CollectionUtil.isEmpty(entities)) {
List<TreeNode<Long>> list = entities.
stream().
map(CategoryServiceImpl::getLongTreeNode).
collect(Collectors.toList());
return TreeUtil.build(list, 0L);
}
return Collections.emptyList();
}
private static TreeNode<Long> getLongTreeNode(CategoryEntity item) {
TreeNode<Long> treeNode = new TreeNode<>();
treeNode.setId(item.getCatId());
treeNode.setParentId(item.getParentCid());
treeNode.setName(item.getName());
treeNode.setWeight(item.getSort());
Map<String, Object> extra = new HashMap<>();
extra.put("showStatus", item.getShowStatus());
extra.put("catLevel", item.getCatLevel());
extra.put("icon", item.getIcon());
extra.put("productUnit", item.getProductUnit());
extra.put("productCount", item.getProductCount());
treeNode.setExtra(extra);
return treeNode;
}
}
測試
public static void main(String[] args) {
List<Tree<Long>> trees = listWithTree1();
System.out.println(JSONUtil.toJsonPrettyStr(trees));
}
方式五
基于mybatisplus的@TableName里面的resultMap屬性,當(dāng)發(fā)生查詢時,會根據(jù)配置的xml查詢SQL進行查詢
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.xw.mapper.FuncMapper">
<resultMap id="thCloudFuncMap" type="com.xw.entity.Func">
<id column="id" property="id"/>
<result column="creator" property="creator"/>
<result column="creator_name" property="creatorName"/>
<result column="updater" property="updater"/>
<result column="updater_name" property="updaterName"/>
<result column="code" property="code"/>
<result column="name" property="name"/>
<result column="icon" property="icon"/>
<result column="note" property="note"/>
<result column="parent_id" property="parentId"/>
<result column="sort" property="sort"/>
<result column="component_name" property="componentName"/>
<result column="type" property="type"/>
<collection column="id" property="children" select="findByParentId" ofType="com.telehot.tpf.dev.rolemenu.entity.ThCloudFunc">
</collection>
</resultMap>
<select id="findByParentId" resultMap="funcMap">
SELECT * FROM func WHERE parent_id = #{parentId}
</select>
<select id="findAll" resultMap="funcMap">
SELECT * FROM func where is_disabled = 0
</select>
</mapper>
實體類
@TableName(value = "func", resultMap = "funcMap")
public class Func extends Entity {
/**
* 編碼
*/
private String code;
/**
* 菜單名稱
*/
private String name;
/**
* 圖標(biāo)
*/
private String icon;
/**
* 圖標(biāo)
*/
private String selectIcon;
/**
* 說明
*/
private String note;
/**
* 父類ID
*/
private Long parentId;
/**
* 排序
*/
private Integer sort;
/**
* 類型
*/
private Integer type;
/**
* 路徑
*/
private String path;
/**
* 應(yīng)用id
*/
private String appId;
/***
* 組件名
*/
private String componentName;
/**
* 層級
*/
private Integer tier;
@TableField(exist = false)
private List<Func> children;
}
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于mybatis-plus邏輯刪除自動填充更新時間的問題
mybatis-plus是對mybatis的增強,mybatis-plus更像是面向?qū)ο缶幊蹋瑪?shù)據(jù)庫基本CRUD的操作可以不用手動編寫SQL語句,大大提高了開發(fā)的效率,這篇文章主要介紹了mybatis-plus邏輯刪除自動填充更新時間問題,需要的朋友可以參考下2022-07-07
spring?jpa集成依賴的環(huán)境準(zhǔn)備及實體類倉庫編寫教程
這篇文章主要為大家介紹了spring?jpa集成依賴的環(huán)境準(zhǔn)備及實體類倉庫編寫教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03
Java中的CyclicBarrier循環(huán)柵欄解析
這篇文章主要介紹了Java中的CyclicBarrier循環(huán)柵欄解析,從字面上的意思可以知道,這個類的中文意思是"循環(huán)柵欄",大概的意思就是一個可循環(huán)利用的屏障,它的作用就是會讓所有線程都等待完成后才會繼續(xù)下一步行動,需要的朋友可以參考下2023-12-12
Java實現(xiàn)Excel文件轉(zhuǎn)PDF(無水印無限制)
這篇文章主要為大家詳細介紹了如何利用Java語言實現(xiàn)Excel文件轉(zhuǎn)PDF的效果,并可以無水印、無限制。文中的示例代碼講解詳細,需要的可以參考一下2022-06-06

