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,将实体数据拷贝到目标类型
将拷贝过数据的目标类型添加到集合中
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种实现方式的文章就介绍到这了,更多相关java返回前端树形结构数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!