Javaはフロントエンドツリー構造データを返します(2つの実装方法)

0. 想い

まず第 1 レベルのディレクトリ (カテゴリ) を検索し、次に第 1 レベルのディレクトリ (カテゴリ) からすべてのサブディレクトリ (カテゴリ) を再帰的に取得し、それらを結合して「ディレクトリ ツリー」を作成します。

1. 通常の実装: コントローラー層は、第 1 レベルのディレクトリ層であるレイヤー 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クラスコレクションのエンティティクラスコレクションとツールクラス

入力パラメータは、不明なタイプのエンティティ コレクションと、ターゲット コレクションの汎用バイトコード タイプ (クラス名.クラス) です。

最終結果を保存する新しいコレクションを作成します。ジェネリックはターゲット型 T です。

エンティティのコレクションをループする

クラスを通じてコン​​ストラクターを取得し、新しいインスタンスを作成します

BeanUtils.copyProperties を使用してエンティティ データをターゲット タイプにコピーする

コピーされたデータのターゲット タイプをコレクションに追加します

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

おすすめ

転載: blog.csdn.net/qq_35207086/article/details/133764215