【JAVA】List<Object>类型构建树结构数据

文章展示了如何使用JAVA和Lombok库构建树形结构数据,包括树形实体类的设计,数据构造,以及通过递归方法转换列表为树形结构的实现过程。提供了一个模拟国家和城市的例子,解释了如何从扁平数据构建层次结构。

前言

JAVA构建树形结构数据案例。

树形实体类

代码如下(示例):
get() || set() 方法就省略了,此处用lombok@Data注解代替

@Data
public class TreeBean {
    /**
     * id
     */
    private String id;
    /**
     * 名称
     */
    private String name;
    /**
     * 上级id
     */
    private String parentId;
    /**
     * 子集 集合
     */
    private List<TreeBean> children;

    /**
     * 无参构造
     */
    public TreeBean() {
    }

    /**
     * 自定义构造方法,省略子集变量
     * @param id
     * @param name
     * @param parentId
     */
    public TreeBean(String id, String name, String parentId) {
        this.id = id;
        this.name = name;
        this.parentId = parentId;
    }
}

lombok依赖坐标如下:

 <dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <version>1.18.18</version>
 </dependency>

数据构造示例

模拟数据

代码如下(示例):

@GetMapping("childrenTest")
    @ApiOperation(value = "树型结构数据测试接口",notes = "树型结构数据测试接口")
    public ResponseEntity<List<TreeBean>> childrenTest(){
    	// 造假数据,真实环境下通过数据库查询。
    	// new TreeBean("id","名称","父级id")
        List<TreeBean> list = new ArrayList<>();
        list.add(new TreeBean("001","中国","0"));
        list.add(new TreeBean("002","美国","0"));
        list.add(new TreeBean("003","俄罗斯","0"));
        list.add(new TreeBean("1","北京","001"));
        list.add(new TreeBean("2","天津","001"));
        list.add(new TreeBean("3","东城区","1"));
        list.add(new TreeBean("4","西城区","1"));
        list.add(new TreeBean("5","朝阳区","1"));
        list.add(new TreeBean("6","和平区","2"));
        list.add(new TreeBean("7","旧金山","002"));
        list.add(new TreeBean("8","圣彼得堡","002"));
        //调用构建树结构数据方法
        List<TreeBean> children = getChildren(list, "0");
        return ResponseEntity.ok(children);
    }

递归构造数据

代码如下(示例):

/**
 *构建树形结构数据
 * @param beanList:数据集合
 * @param parentId:父级标识(初始因该为最顶级的标识)
 * @return
 */
public static List<TreeBean> getChildren(List<TreeBean> beanList,String parentId){
    //创建返回树结构数据集合
    List<TreeBean> treeList = new ArrayList<>();
    for (TreeBean bean : beanList) {
        //创建当前节点的bean
        TreeBean treeBean = new TreeBean();
        //创建当前节点下子节点的数据集合
        List<TreeBean> childrenList = new ArrayList<>();
        //如果当前节点等于【参数】父节点,则进行递归操作
        if (parentId.equals(bean.getParentId())){
            //将节点数据复制到当前bean下,也就是上面创建的【treeBean对象】
            BeanUtils.copyProperties(bean,treeBean);
            //递归查询当前节点是否有子节点
            childrenList = getChildren(beanList,bean.getId());
            //有则将子节点的数据集合添加到当前bean下
            if (childrenList.size()>0){
                treeBean.setChildren(childrenList);
            }
            //将当前构建的树对象放入返回集合中
            treeList.add(treeBean);
        }
    }
    return treeList;
}

测试案例

[
  {
    "id": "001",
    "name": "中国",
    "parentId": "0",
    "children": [
      {
        "id": "1",
        "name": "北京",
        "parentId": "001",
        "children": [
          {
            "id": "3",
            "name": "东城区",
            "parentId": "1",
            "children": null
          },
          {
            "id": "4",
            "name": "西城区",
            "parentId": "1",
            "children": null
          },
          {
            "id": "5",
            "name": "朝阳区",
            "parentId": "1",
            "children": null
          }
        ]
      },
      {
        "id": "2",
        "name": "天津",
        "parentId": "001",
        "children": [
          {
            "id": "6",
            "name": "和平区",
            "parentId": "2",
            "children": null
          }
        ]
      }
    ]
  },
  {
    "id": "002",
    "name": "美国",
    "parentId": "0",
    "children": [
      {
        "id": "7",
        "name": "旧金山",
        "parentId": "002",
        "children": null
      },
      {
        "id": "8",
        "name": "圣彼得堡",
        "parentId": "002",
        "children": null
      }
    ]
  },
  {
    "id": "003",
    "name": "俄罗斯",
    "parentId": "0",
    "children": null
  }
]

/** * 根据文章id或者视频id查询评论 * * @param id 文章id或者视频id * @return Map<String, Object> */ public List<Map<String, Object>> getCommentByArticleId(Long id) { LambdaQueryWrapper<CmsArticleComment> lqw = new LambdaQueryWrapper<>(); lqw.orderByDesc(CmsArticleComment::getCreateTime); lqw.eq(CmsArticleComment::getArticleId, id); List<CmsArticleCommentVo> cmsArticleCommentVoList = commentMapper.selectVoList(lqw); Set<Long> userIdList = new HashSet<>(); Map<Long, List<CmsArticleCommentVo>> treeMap = new HashMap<>(); for (CmsArticleCommentVo comment : cmsArticleCommentVoList) { userIdList.add(comment.getCommentUserId()); Long parentId = comment.getParentId(); if (parentId != null && parentId == 0) { parentId = null; } treeMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(comment); } List<CmsArticleCommentVo> parentList = treeMap.get(null); QueryWrapper<CmsMiniUserCommentLike> wrapper = new QueryWrapper<>(); wrapper.eq("mini_user_id", LoginHelper.getUserId()); wrapper.eq("article_id", id); List<CmsMiniUserCommentLike> cmsMiniUserCommentLikes = miniUserCommentLikeMapper.selectList(wrapper); Set<Long> collect = cmsMiniUserCommentLikes.stream().map(CmsMiniUserCommentLike::getCommentId).collect(Collectors.toSet()); // 获取用户信息 List<CmsMiniUserVo> cmsMiniUsers = miniUserMapper.selectVoByIds(userIdList); // 批量查询用户头像 List<String> list = cmsMiniUsers.stream().map(CmsMiniUserVo::getAvatar).toList(); List<SysOss> sysOssList = sysOssMapper.selectByIds(list); Map<Long, SysOss> sysOssMap = sysOssList.stream().collect(Collectors.toMap(SysOss::getOssId, i -> i)); cmsMiniUsers.forEach(cmsMiniUser -> { cmsMiniUser.setAvatarUrl(sysOssMap.get(Long.valueOf(cmsMiniUser.getAvatar())).getUrl()); }); Map<Long, CmsMiniUserVo> cmsMiniUserMap = cmsMiniUsers.stream().collect(Collectors.toMap(CmsMiniUserVo::getId, i -> i)); return buildCommentData(cmsMiniUserMap,parentList, treeMap, collect); } /** * 组装评论数据 二层级 * @return List<Map<String, Object>> */ public List<Map<String, Object>> buildCommentData(Map<Long, CmsMiniUserVo> cmsMiniUserMap, List<CmsArticleCommentVo> parentList, Map<Long, List<CmsArticleCommentVo>> treeMap, Set<Long> collect) { List<Map<String, Object>> commentData = new ArrayList<>(); if (parentList == null || parentList.isEmpty()) { return commentData; } if (treeMap == null) { treeMap = new HashMap<>(); } if (collect == null) { collect = new HashSet<>(); } for (CmsArticleCommentVo comment : parentList) { // 只处理父级评论(parentId为null) if (comment.getParentId() != null) { continue; } Map<String, Object> map = buildCommentMap(comment, collect, cmsMiniUserMap); // 获取所有子评论(包括直接子评论和孙子评论等) List<Map<String, Object>> childrenMaps = new ArrayList<>(); List<CmsArticleCommentVo> directChildren = treeMap.get(comment.getId()); if (directChildren != null && !directChildren.isEmpty()) { // 添加直接子评论 for (CmsArticleCommentVo child : directChildren) { childrenMaps.add(buildCommentMap(child, collect, cmsMiniUserMap)); // 添加孙子及更深层级的评论 addAllDescendants(cmsMiniUserMap, child, treeMap, childrenMaps, collect); } } map.put("children", childrenMaps); commentData.add(map); } return commentData; } /** * 构建单个评论的Map表示 */ private Map<String, Object> buildCommentMap(CmsArticleCommentVo comment, Set<Long> collect, Map<Long, CmsMiniUserVo> cmsMiniUserMap) { Map<String, Object> map = new HashMap<>(); map.put("id", comment.getId()); map.put("userId", comment.getCommentUserId()); map.put("avatar",cmsMiniUserMap.get(comment.getCommentUserId()).getAvatarUrl()); map.put("articleId", comment.getArticleId()); map.put("createTime", comment.getCreateTime()); map.put("name", comment.getCommentName()); map.put("parentId", comment.getParentId()); map.put("parentName", comment.getParentName()); map.put("numberLike", comment.getNumberLike()); map.put("ip", comment.getIpAddress()); map.put("content", comment.getCommentContent()); map.put("isLike", collect.contains(comment.getId())); return map; } /** * 递归添加所有后代评论到列表中 */ private void addAllDescendants( Map<Long, CmsMiniUserVo> cmsMiniUserMap, CmsArticleCommentVo parent, Map<Long, List<CmsArticleCommentVo>> treeMap, List<Map<String, Object>> childrenMaps, Set<Long> collect) { List<CmsArticleCommentVo> children = treeMap.get(parent.getId()); if (children != null && !children.isEmpty()) { for (CmsArticleCommentVo child : children) { childrenMaps.add(buildCommentMap(child, collect, cmsMiniUserMap)); // 递归添加更深层级 addAllDescendants(cmsMiniUserMap,child, treeMap, childrenMaps, collect); } } } 重构优化代码
11-06
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值