java返回前端树形结构数据(2种实现方式)

这篇具有很好参考价值的文章主要介绍了java返回前端树形结构数据(2种实现方式)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0.思想

首先找到一级目录(类别),然后从一级目录(类别)递归获取所有子目录(类别),并组合成为一个“目录树”

1.普通实现:controller层传的是0层,就是一级目录层,从这里开始往下递归。

/**
     * 递归查询得到,分类目录数据;(针对前台的)
     * @return
     */
    @Override
    public List<CategoryVO> listCategoryForCustomer() {
        //定义一个List,这个List就用来存在最终的查询结果;即,这个List中的直接元素是:所有的parent_id=0,即type=1的,第1级别的目录;
        List<CategoryVO> categoryVOList = new ArrayList<CategoryVO>();
 
        //我们额外创建recursivelyFindCategories()方法,去实现递归查询的逻辑;
        //我们第一次递归查询时,是先查一级目录;(而一级目录的parentId是0)
        //该方法第一个参数是:List<CategoryVO> categoryVOList:用来存放当前级别对应的,所有的下一级目录数据;
        //  PS:对于【最终返回给前端的List<CategoryVO> categoryVOList】来说,其所谓的下一级目录就是:所有的parent_id=0,即type=1的,第1级别的目录;
        //  PS:对于【所有的parent_id=0,即type=1的,第1级别的目录;】来说,其categoryVOList就是【List<CategoryVO> childCategory属性】,其是用来存放该级别对应的所有的parent_id=1,即type=2的,第2级别的目录;
        //  PS:对于【所有的parent_id=1,即type=2的,第2级别的目录;】来说,其categoryVOList就是【List<CategoryVO> childCategory属性】,其是用来存放该级别对应的所有的parent_id=2,即type=3的,第3级别的目录;
        //该方法的第二个参数是:当前级别目录的parent_id,即也就是当前级别的上一级目录的id;
        //即,第一个参数是【上一级别的List<CategoryVO> categoryVOList】;第二参数是【下一级别的parent_id,也就是当前级别的id】;
        recursivelyFindCategories(categoryVOList, 0);
        return categoryVOList;
    }
 
    /**
     * 递归查询分类目录数据的,具体逻辑;;;其实就是,递归获取所有目录分类和子目录分类,并组合称为一个“目录树”;
     * @param categoryVOList :存放所有下级别分类目录的数据;
     * @param parentId :某级分类目录的parentId;
     */
    private void recursivelyFindCategories(List<CategoryVO> categoryVOList, Integer parentId) {
        //首先,根据parent_id,查询出所有该级别的数据;(比如,第一次我们查询的是parent_id=0,即type=1的,第1级别的目录)
        List<Category> categoryList = categoryMapper.selectCategoriesByParentId(parentId);
        //然后,遍历上面查询的该级别的数据;去尝试查询该级别数据的,下一级别的数据;
        if (!CollectionUtils.isEmpty(categoryList)) {
            //遍历所有查到的当前级别数据,把其放在对应上级目录的【List<CategoryVO> categoryVOList】中;
            for (int i = 0; i < categoryList.size(); i++) {
                //获取到【上面查询的,该级别数据中的,一条数据】,把其存储到上级目录的List<CategoryVO> childCategory属性中;
                //自然,如果该级别是【parent_id=0,即type=1的,第1级别的目录】,就是把其存储在最顶级的、返回给前端的那个List<CategoryVO> categoryVOS中;
                Category category =  categoryList.get(i);
                CategoryVO categoryVo = new CategoryVO();
                BeanUtils.copyProperties(category, categoryVo);
                categoryVOList.add(categoryVo);
 
                //然后,这一步是关键:针对【每一个当前级别的,目录数据】去递归调用recursivelyFindCategories()方法;
                //自然,第一个参数是【当前级别数据的,List<CategoryVO> childCategory属性】:这是存放所有下级别目录数据的;
                //第二个参数是【当前级别数据的id】:这自然是下级别目录数据的parent_id:
                recursivelyFindCategories(categoryVo.getChildCategory(), categoryVo.getId());
            }
        }
    }

2.stream流实现:

  /**
     * 利用stream 流实现
     *
     */
    @Override
    public List<CategoryVO> listTree() {
        //1.查出所有分类
        List<Category> categories = categoryMapper.selectList();
        //转成VO实体集合类
        List<CategoryVO> categoryVOS = new ArrayList<>();
        //ArrayListBeanUtils.copyProperties(categories,categoryVOS);
        //注意BeanUtils.copyProperties无法直接复制集合,要循环;也可以单独写一个工具类,
        //后续补充转换集合工具类
        for (Category category:categories
             ) {
            CategoryVO categoryVO = new CategoryVO();
            BeanUtils.copyProperties(category,categoryVO);
            categoryVOS.add(categoryVO);
        }
        //2.组装成父子的树形结构
        //2.1 找到所有的一级分类
        List<CategoryVO> collect = categoryVOS.stream().filter(categoryVO -> {
            return categoryVO.getParentId() == 0;//一级分类就是父id=0是吧
        }).map(menu -> {
            menu.setChildCategory(getChildrens(menu,categoryVOS));
            return menu;
        }).sorted((menu1,menu2)->{//目录排序
            return (menu1.getOrderNum() ==null?0:menu1.getOrderNum() )- (menu2.getOrderNum() == null?0:menu2.getOrderNum());
        }).collect(Collectors.toList());

        return collect;
    }

    //递归查找所有菜单的子菜单
    //root 当前菜单,categoryList是菜单集合
    private List<CategoryVO> getChildrens(CategoryVO root, List<CategoryVO> categoryList) {
        //找出当前菜单的子菜单
        List<CategoryVO> children = categoryList.stream().filter(categoryVO -> {
            //当前菜单root的id等于(是)菜单集合中菜单的父Id,那就意味着当前菜单就是子菜单
            //当前菜单root的id,是其他菜单的父id,意味着当前菜单的子菜单找到了呗
            return categoryVO.getParentId() == root.getId();
        }).map(categoryVO -> {
            //找到子菜单
            categoryVO.setChildCategory(getChildrens(categoryVO, categoryList));
            return categoryVO;
        }).sorted((menu1,menu2)->{
            //菜单的排序
            return (menu1.getOrderNum() ==null?0:menu1.getOrderNum() )- (menu2.getOrderNum() == null?0:menu2.getOrderNum());
        }).collect(Collectors.toList());

        return children;
    }

3.实体类集合专VO类集合的工具类

入参为未知类型的实体集合与目标集合的泛型字节码类型(类名.class)

创建一个新集合用来存储最终结果,泛型为目标类型T

遍历循环实体集合

通过Class获取构造器并创建新的实例

使用BeanUtils.copyProperties,将实体数据拷贝到目标类型

将拷贝过数据的目标类型添加到集合中文章来源地址https://www.toymoban.com/news/detail-764416.html

public static <T> List<T> entityListToVOList(List<?> list, Class<T> clazz) {
    List<T> result = new ArrayList<>(list.size());
    for (Object source : list) {
        T target;
        try {
            target = clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException();
        }
        BeanUtils.copyProperties(source, target);
        result.add(target);
    }
    return result;
}

到了这里,关于java返回前端树形结构数据(2种实现方式)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java 数据结构篇-二叉树的深度优先遍历(实现:递归方式、非递归方式)

    Java 数据结构篇-二叉树的深度优先遍历(实现:递归方式、非递归方式)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍    文章目录         1.0 二叉树的说明         1.1 二叉树的实现         2.0 二叉树的优先遍历说明         3.0 用递归方式实现二叉树遍历         3.1 用递归方式实现遍历 - 前序遍历         3.2 用递归

    2024年02月05日
    浏览(10)
  • 后端java 如何返回给前端 JSON数据

    在上述代码中,@ResponseBody注解用于将Java List对象转换为JSON格式的数据,并返回给前端。Spring会自动将List对象转换为JSON格式的数组,其中每个元素都是一个JSON对象。在本例中,每个JSON对象都包含一个name属性和一个age属性。 Regenerate

    2024年02月15日
    浏览(11)
  • 超大量数据,前端树形结构展示

    后端返回了50万数据,让前端一次性展示成树,之前用的ant-design-vue的tree插件,卡的死死的,经过大量实验,现发现三种树可以支持如此大数量的数据。 目录 第一种:vue-easy-tree 使用方式: 1.安装插件 2.引入插件 全局引入 组件引入 3.使用  在使用虚拟滚动时,必须设置 no

    2024年01月21日
    浏览(14)
  • Java后端向前端返回文件流——实现下载功能

    Java后端向前端返回文件流——实现下载功能

    前端实现文件下载功能有多种方法,这里就不一一介绍,这里只介绍使用文件流下载的实现方法。 既然是文件流那就肯定需要给前端返回一堆二进制编码,作为后端就可以返回一个 OutPutStream 后端可以使用Java中servlet提供的 HttpServletResponse ,核心步骤是要设置响应的数据类型

    2024年02月11日
    浏览(11)
  • Java后端向前端返回文件流——实现下载功能!

    Java后端向前端返回文件流——实现下载功能!

    前端实现文件下载功能有多种方法,这里就不一一介绍,这里只介绍使用文件流下载的实现方法。 既然是文件流那就肯定需要给前端返回一堆二进制编码,作为后端就可以返回一个 OutPutStream 后端可以使用Java中servlet提供的 HttpServletResponse ,核心步骤是要设置响应的数据类型

    2024年02月08日
    浏览(12)
  • java返回前端实体类json数据时如何忽略某个属性

    第一种方法 SpringBoot中忽略实体类中的某个属性不返回给前端的方法:使用Jackson的方式://第一种方式,使用@JsonIgnore注解标注在属性上, 第二种方法 使用@JsonIgnoreProperties标注在类上,可以忽略指定集合的属性 注意 :同时使用@JsonProperty和@JsonIgnore时,可能会导致@JsonIgnore失效

    2024年02月13日
    浏览(10)
  • 线程方法接收参数和返回参数,Java的两种线程实现方式对比

    总所周知,Java实现多线程有两种方式,分别是继承Thread类和实现Runable接口,那么它们的区别是什么? 继承 Thread 类: 通过继承 Thread 类,你可以创建一个直接表示线程的类。你可以覆盖 Thread 类中的 run 方法来定义线程的逻辑。当调用 start 方法启动线程时,会执行该类中的

    2024年02月11日
    浏览(13)
  • java实现文件的上传和下载,将文件流转base64返回给前端

    上传代码 文件下载代码 后端通过json拿到文件流的返回,我采用将文件流转成base64返回给前台,实现代码如下:

    2024年02月13日
    浏览(16)
  • Java 高效构建树形结构

    构造树形结构通常使用递归遍历元素,构造元素的子集,直至子级全部构建完成,返回父级,最终完成树的构建,这种方法的时间复杂度基本上在 O ( N 2 ) O(N^2) O ( N 2 ) ,数据量比较大的时候性能大幅下降,耗时严重。通过不断实践与优化,得出一种可将构造树形结构的性能提

    2024年02月16日
    浏览(9)
  • 解决:Java后端返回给前端的Date格式数据相差8小时的问题

    问题描述: 后端得到的数据是对的,但是返回给前端后,数据比原数据慢了8小时。 原因: json数据在返回浏览器端是会被spring-boot默认的Jackson框架转换,而Jackson框架默认的时区GMT(相对于中国是少了8小时)。 解决: 在application.yml文件中,配置

    2024年04月16日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包