Java递归/遍历,实现遍历父子级菜单

目录

准备工作

迭代实现

递归实现

未带有显示顺序的递归遍历

sid的树结构

java实现CRUD思路

service

serviceImpl

controller

mybatis plus分页思路

service

serviceImpl

controller

树结构漏洞补差2.0


准备工作

create table dormitory_management.fuzi
(
    menu_id       bigint auto_increment comment '菜单ID'
        primary key,
    menu_name     varchar(50)      not null comment '菜单名称',
    parent_id     bigint default 0 null comment '父菜单ID',
    display_order int    default 0 null comment '显示顺序'
);

-- 添加中文测试数据
INSERT INTO dormitory_management.fuzi (menu_name, parent_id, display_order) VALUES
('顶级菜单1', 0, 1),
('顶级菜单2', 0, 2),
('子菜单1-1', 1, 1),
('子菜单1-2', 1, 2),
('子菜单2-1', 2, 1);
@Data
@ToString
public class Fuzi {
    private Long menuId;
    private String menuName;
    private Long parentId;
    private Long  displayOrder;
    private List<Fuzi> children; // 子菜单列表
}

迭代实现

分析图:


//Service层
public interface FuziService extends IService<Fuzi> {
    List<Fuzi> getFuziMenuTreeWithoutChildren();

    List<Fuzi> buildMenuTree(List<Fuzi> menuList);
}
package com.lyh.mp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lyh.mp.entity.Fuzi;
import com.lyh.mp.mapper.FuziMapper;
import com.lyh.mp.service.FuziService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author Mtz
 * @version 1.0
 * @2024/2/2015:49
 * @function
 * @comment
 */
@Service
public class FuziServiceImpl extends ServiceImpl<FuziMapper, Fuzi> implements FuziService {


    @Autowired
    private FuziMapper fuziMapper;


    public List<Fuzi> getFuziMenuTreeWithoutChildren() {
        QueryWrapper<Fuzi> fuzi = new QueryWrapper<>();
        fuzi.select("menu_id", "menu_name", "parent_id","display_order"); // 指定查询的字段
        List<Fuzi> menuList = fuziMapper.selectList(fuzi);
        return buildMenuTree(menuList); // 构建菜单树
    }

    // 构建父子级菜单树
    public List<Fuzi> buildMenuTree(List<Fuzi> menuList) {
        Map<Long, Fuzi> menuMap = new HashMap<>();

        // 将菜单放入Map中,以菜单ID作为键
        for (Fuzi menu : menuList) {
            menuMap.put(menu.getMenuId(), menu);
        }

        // 遍历菜单列表,将子菜单添加到对应的父菜单的children属性中
        List<Fuzi> treeMenu = new ArrayList<>();
        for (Fuzi menu : menuList) {
            Long parentId = menu.getParentId();
            if (parentId == null || parentId == 0) {
                // 顶级菜单
                treeMenu.add(menu);
            } else {
                // 子菜单
                Fuzi parentMenu = menuMap.get(parentId);
                if (parentMenu != null) {
                    if (parentMenu.getChildren() == null) {
                        parentMenu.setChildren(new ArrayList<>());
                    }
                    parentMenu.getChildren().add(menu);
                }
            }
        }

        // 对顶级菜单及其子菜单按照 display_order 排序
        sortTreeMenu(treeMenu);

        return treeMenu;
    }

    // 递归排序树形结构的菜单
    private void sortTreeMenu(List<Fuzi> treeMenu) {
        for (Fuzi menu : treeMenu) {
            if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
                // 递归排序子菜单
                sortTreeMenu(menu.getChildren());
            }
        }

        // 对当前层级的菜单按照 display_order 排序
        Collections.sort(treeMenu, Comparator.comparingLong(Fuzi::getDisplayOrder));
    }
    /*
    - Fuzi(menuId=1, menuName=顶级菜单1, parentId=0, displayOrder=1, children=[
  - Fuzi(menuId=3, menuName=子菜单1-1, parentId=1, displayOrder=1, children=null),
  - Fuzi(menuId=4, menuName=子菜单1-2, parentId=1, displayOrder=2, children=null)
  ])

- Fuzi(menuId=2, menuName=顶级菜单2, parentId=0, displayOrder=2, children=[
  - Fuzi(menuId=5, menuName=子菜单2-1, parentId=2, displayOrder=1, children=null)
  ])

     */
}

递归实现


    // 构建父子级菜单树
    public List<Fuzi> buildMenuTree(List<Fuzi> menuList) {
        Map<Long, Fuzi> menuMap = new HashMap<>();
        for (Fuzi menu : menuList) {
            menuMap.put(menu.getMenuId(), menu);
        }

        List<Fuzi> treeMenu = new ArrayList<>();
        for (Fuzi menu : menuList) {
            if (menu.getParentId() == null || menu.getParentId() == 0) {
                buildChildMenu(menu, menuMap);
                treeMenu.add(menu);
            }
        }

        return treeMenu;
    }

    private void buildChildMenu(Fuzi parentMenu, Map<Long, Fuzi> menuMap) {
        Long parentId = parentMenu.getMenuId();
        List<Fuzi> children = new ArrayList<>();

        menuMap.values().stream()
                .filter(menu -> parentId.equals(menu.getParentId()))
                .forEach(menu -> {
                    buildChildMenu(menu, menuMap);
                    children.add(menu);
                });

        children.sort(Comparator.comparingLong(Fuzi::getDisplayOrder));
        parentMenu.setChildren(children);
    }

未带有显示顺序的递归遍历

    public List<Fuzi> getFuziMenuTreeWithoutChildren() {
        QueryWrapper<Fuzi> fuzi = new QueryWrapper<>();
        fuzi.select("menu_id", "menu_name", "parent_id"); // 指定查询的字段
        List<Fuzi> menuList = fuziMapper.selectList(fuzi);
        return buildMenuTree(menuList); // 构建菜单树
    }

    // 构建父子级菜单树
     public List<Fuzi> buildMenuTree(List<Fuzi> menuList) {
        Map<Long, Fuzi> menuMap = new HashMap<>();

        // 将菜单放入Map中,以菜单ID作为键
        for (Fuzi menu : menuList) {
            menuMap.put(menu.getMenuId(), menu);
        }

         System.out.println(menuMap);


        // 遍历菜单列表,将子菜单添加到对应的父菜单的children属性中
        List<Fuzi> treeMenu = new ArrayList<>();
        for (Fuzi menu : menuList) {
            Long parentId = menu.getParentId();
            if (parentId == null || parentId == 0) {
                // 顶级菜单
                treeMenu.add(menu);
            } else {
                // 子菜单
                Fuzi parentMenu = menuMap.get(parentId);
                if (parentMenu != null) {
                    if (parentMenu.getChildren() == null) {
                        parentMenu.setChildren(new ArrayList<>());
                    }
                    parentMenu.getChildren().add(menu);
                }
            }
        }

        return treeMenu;
    }

sid的树结构

    @TableId
    private Long id;
    //分类名称
//    @NotEmpty(message = "分类名称不能为空")
    @NotEmpty(message = "分类名称不能为空")
    private String categoriesName;
    //父类id
//    @NotNull(message = "111")
    private Long categoriesPid;

    @TableField(exist = false)
    private List<ScCategories> categoriesSids;
    
    @TableField(exist = false)
    private List<ScCategories> children;

遍历实现

    public List<ScCategories> buildMenuTree(List<ScCategories> menuList) {
        Map<Long, ScCategories> menuMap = new HashMap<>();

        // 将菜单放入Map中,以菜单ID作为键
        for (ScCategories menu : menuList) {
            menuMap.put(menu.getId(), menu);
        }

        System.out.println(menuMap.values());
        // 遍历菜单列表,将子菜单添加到对应的父菜单的children属性中
        List<ScCategories> treeMenu = new ArrayList<>();
        for (ScCategories categories : menuList) {
            Long parentId = categories.getCategoriesPid();
            Long childId = categories.getCategoriesSid(); // 获取子ID
            if (parentId == null || parentId == 0) {
                // 顶级菜单
                treeMenu.add(categories);
            } else {
                // 子菜单
                ScCategories parentMenu = menuMap.get(parentId);
                if (parentMenu != null) {
                    if (parentMenu.getChildren() == null) {
                        parentMenu.setChildren(new ArrayList<>());
                    }
                    parentMenu.getChildren().add(categories);
                }
            }

            // 将当前分类添加为父分类的子分类
            if (childId != null && childId != 0) {
                ScCategories childMenu = menuMap.get(childId);
                if (childMenu != null) {
                    if (childMenu.getChildren() == null) {
                        childMenu.setChildren(new ArrayList<>());
                    }
                    childMenu.getChildren().add(categories);
                }
            }
        }

        return treeMenu;
    }

java实现CRUD思路

service

public interface ScStoreCategoriesService {


    // 店铺分页查询.
    IPage<ScStoreCategories> selectInfo(ScStoreCategories scStoreCategories, Pageable pageable);

    ResponseEntity<List<ScStoreCategories>> selectInfos(ScStoreCategories scStoreCategories);

    // 根据id 返回
    ResponseEntity<ScStoreCategories> getByIdInfo(ScStoreCategories scStoreCategories);

    // 修改店铺
    ResponseEntity<String> saveOrUpdateInfo(ScStoreCategories scStoreCategories);

    // 删除店铺
    ResponseEntity<String> removeByIdInfo(ScStoreCategories scStoreCategories);

    //添加店铺
    ResponseEntity<String> insertInfo(ScStoreCategories scStoreCategories);

    // 添加店铺的子分类
    ResponseEntity<String> insertInfos(ScStoreCategories scStoreCategories);
}

serviceImpl

package co.yixiang.shopping.service.impl;

import co.yixiang.common.service.impl.BaseServiceImpl;
import co.yixiang.shopping.entity.ScStoreCategories;
import co.yixiang.shopping.mapper.ScStoreCategoriesMapper;
import co.yixiang.shopping.service.ScStoreCategoriesService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Mtz
 * @version 1.0
 * @2024/3/2517:50
 * @function
 * @comment
 */
@Service
public class ScStoreCategoriesServiceImpl extends BaseServiceImpl<ScStoreCategoriesMapper, ScStoreCategories> implements ScStoreCategoriesService {


    @Autowired
    private ScStoreCategoriesMapper scStoreCategoriesMapper;

    @Override
    public IPage<ScStoreCategories> selectInfo(ScStoreCategories scStoreCategories, Pageable pageable) {
        //根据店铺名分页查询
        Page<ScStoreCategories> scStoreCategoriesPage = scStoreCategoriesMapper.selectPage(new Page<>(pageable.getPageNumber(),
                pageable.getPageSize()), new LambdaQueryWrapper<ScStoreCategories>()
                .eq(ScStoreCategories::getCategoriesPid, 0)    // 查出顶级父类
                .like(!Objects.isNull(scStoreCategories.getCategoriesName()),
                        ScStoreCategories::getCategoriesName, scStoreCategories.getCategoriesName()));

        List<ScStoreCategories> storeCategories = scStoreCategoriesPage.getRecords();

        storeCategories.forEach(record -> {
            List<ScStoreCategories> storeCategories2 = scStoreCategoriesMapper.selectList(
                    new LambdaQueryWrapper<ScStoreCategories>()
                            .eq(ScStoreCategories::getCategoriesPid, record.getId()));
            record.setStr("A");
            record.setChildren(storeCategories2);
        });


        return scStoreCategoriesPage;

    }

    @Override
    public ResponseEntity<List<ScStoreCategories>> selectInfos(ScStoreCategories scStoreCategories) {
        // 名字模糊查询
        List<ScStoreCategories> storeCategories = scStoreCategoriesMapper.selectList(
                new LambdaQueryWrapper<ScStoreCategories>()
                        .like(!Objects.isNull(scStoreCategories.getCategoriesName()), ScStoreCategories::getCategoriesName, scStoreCategories.getCategoriesName()));

        List<ScStoreCategories> storeCategories1 = buildMenuTree(storeCategories);



        return ResponseEntity.ok(storeCategories1);
    }
    @Override
    public ResponseEntity<ScStoreCategories> getByIdInfo(ScStoreCategories scStoreCategories) {
        ScStoreCategories storeCategories = scStoreCategoriesMapper.selectById(scStoreCategories.getId());
        return storeCategories != null
                ? ResponseEntity.ok(storeCategories) // 如果查询结果不为 null,返回 OK 状态码和查询到的数据
                : ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); // 如果查询结果为 null,返回 404 NOT FOUND 状态码
    }

    @Override
    public ResponseEntity<String> saveOrUpdateInfo(ScStoreCategories scStoreCategories) {
        return scStoreCategoriesMapper.updateById(scStoreCategories) > 0 ? ResponseEntity.ok("更新成功")
                : ResponseEntity.status(HttpStatus.BAD_REQUEST).body("更新失败");
    }

    @Override
    public ResponseEntity<String> removeByIdInfo(ScStoreCategories scStoreCategories) {
        // 查看是否还有子节点
        boolean hasChildren = hasChildren(scStoreCategories.getCategoriesPid());

        if (hasChildren == true) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("还有子结点");
        }

        return scStoreCategoriesMapper.deleteById(scStoreCategories.getId()) > 0 ? ResponseEntity.ok("删除成功") :
                ResponseEntity.status(HttpStatus.NOT_FOUND).body("删除失败");
    }

    @Override
    public ResponseEntity<String> insertInfo(ScStoreCategories scStoreCategories) {
        return scStoreCategoriesMapper.insert(scStoreCategories) > 0 ? ResponseEntity.ok("添加成功") : ResponseEntity.status(HttpStatus.NOT_FOUND).body("添加失败");
    }

    //  添加店铺子分类
    @Override
    public ResponseEntity<String> insertInfos(ScStoreCategories scStoreCategories) {

        // 子分类的 pid 设置为 父的 id  ,name -- name ,
        ScStoreCategories storeCategories = new ScStoreCategories();
        storeCategories.setCategoriesPid(scStoreCategories.getId());
        storeCategories.setCategoriesName(scStoreCategories.getCategoriesName());

        return scStoreCategoriesMapper.insert(storeCategories) > 0 ? ResponseEntity.ok("添加成功") : ResponseEntity.status(HttpStatus.NOT_FOUND).body("添加失败");
    }

    private boolean hasChildren(Long parentId) {
        Long count = scStoreCategoriesMapper.selectCount(new LambdaQueryWrapper<ScStoreCategories>()
                .eq(ScStoreCategories::getCategoriesPid, parentId));
        return count > 0;
    }


    // 构建父子级菜单树
    public List<ScStoreCategories> buildMenuTree(List<ScStoreCategories> menuList) {
        Map<Long, ScStoreCategories> menuMap = new HashMap<>();

        // 将菜单放入Map中,以菜单ID作为键
        for (ScStoreCategories menu : menuList) {
            menuMap.put(menu.getId(), menu);
        }

        // 遍历菜单列表,将子菜单添加到对应的父菜单的children属性中
        List<ScStoreCategories> treeMenu = new ArrayList<>();
        for (ScStoreCategories menu : menuList) {
            Long parentId = menu.getCategoriesPid();
            if (parentId == null || parentId == 0) {
                // 顶级菜单
                treeMenu.add(menu);
            } else {
                // 子菜单
                ScStoreCategories parentMenu = menuMap.get(parentId);
                if (parentMenu != null) {
                    if (parentMenu.getChildren() == null) {
                        parentMenu.setChildren(new ArrayList<>());
                    }
                    parentMenu.getChildren().add(menu);
                }
            }
        }
        return treeMenu;
    }


}

controller

package co.yixiang.shopping.controller;

import co.yixiang.shopping.entity.ScStoreCategories;
import co.yixiang.shopping.service.ScStoreCategoriesService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author Mtz
 * @version 1.0
 * @2024/3/2518:37
 * @function
 * @comment
 */
@RestController
@RequestMapping("/storecategories")
public class ScStoreCategoriesController {
    @Autowired
    private ScStoreCategoriesService scStoreCategoriesService;

    // 店铺分页查询.
    @GetMapping("/list")
    public ResponseEntity<IPage<ScStoreCategories>> selectInfo(ScStoreCategories scStoreCategories, Pageable pageable) {
        return ResponseEntity.ok(scStoreCategoriesService.selectInfo(scStoreCategories, pageable));
    }


    @GetMapping("/selectInfos")
    public ResponseEntity<List<ScStoreCategories>> selectInfos(ScStoreCategories scStoreCategories) {
        return scStoreCategoriesService.selectInfos(scStoreCategories);
    }


    // 根据id查询店铺
    @GetMapping("/getbyid")
    public ResponseEntity<ScStoreCategories> getByIdInfo(ScStoreCategories scStoreCategories) {
        return scStoreCategoriesService.getByIdInfo(scStoreCategories);
    }

    // 修改店铺信息
    @PostMapping("/saveOrUpdateInfo")
    public ResponseEntity<String> saveOrUpdateInfo(@RequestBody ScStoreCategories scStoreCategories) {
        return scStoreCategoriesService.saveOrUpdateInfo(scStoreCategories);
    }

    // 删除店铺
    @PostMapping("/removeByIdInfo")
    public ResponseEntity<String> removeByIdInfo(@RequestBody ScStoreCategories scStoreCategories) {
        return scStoreCategoriesService.removeByIdInfo(scStoreCategories);
    }

    // 添加店铺
    @PostMapping("/insertInfo")
    public ResponseEntity<String> insertInfo(@RequestBody ScStoreCategories scStoreCategories) {
        return scStoreCategoriesService.insertInfo(scStoreCategories);
    }

    // 添加子店铺
    @PostMapping("/insertInfos")
    public ResponseEntity<String> insertInfos(@RequestBody ScStoreCategories scStoreCategories) {
        return scStoreCategoriesService.insertInfos(scStoreCategories);
    }
}

mybatis plus分页思路

service

    /**
     * 分页查询物流信息
     */
    IPage<ScStoreCategories> selectInfoa(ScStoreCategories scStoreCategories, Pageable pageable);

serviceImpl

    @Override
    public IPage<ScStoreCategories> selectInfoa(ScStoreCategories scStoreCategories, Pageable pageable) {
        //查询全部的数据
        List<ScStoreCategories> storeCategoriesA = scStoreCategoriesMapper.selectList(null);


        Page<ScStoreCategories> scStoreCategoriesPage = scStoreCategoriesMapper.selectPage(
                new Page<>(pageable.getPageNumber(), pageable.getPageSize()),
                new LambdaQueryWrapper<ScStoreCategories>()
                        .eq(ScStoreCategories::getCategoriesPid,0)
                        .like(!Objects.isNull(scStoreCategories.getCategoriesName()), ScStoreCategories::getCategoriesName, scStoreCategories.getCategoriesName())
        );
           //查询的顶级集合
        List<ScStoreCategories> storeCategoriesList = scStoreCategoriesPage.getRecords();

        // 构建树结构
        List<ScStoreCategories> storeCategoriesB = buildMenuTree(storeCategoriesA);


// 从 storeCategoriesList 集合中提取名称
        List<String> categoryNames = storeCategoriesList.stream()
                .map(ScStoreCategories::getCategoriesName) // 获取名称
                .collect(Collectors.toList());

// 使用名称数据来筛选 storeCategoriesB 集合中的元素
        List<ScStoreCategories> filteredCategoriesB = storeCategoriesB.stream()
                .filter(category -> categoryNames.contains(category.getCategoriesName()))
                .collect(Collectors.toList());

        scStoreCategoriesPage.setRecords(filteredCategoriesB);
        return scStoreCategoriesPage;
    }

controller

    @GetMapping("/selectInfoa")
    public   IPage<ScStoreCategories> selectInfoa(ScStoreCategories scStoreCategories, Pageable pageable) {
        return scStoreCategoriesService.selectInfoa(scStoreCategories, pageable);
    }

树结构漏洞补差2.0

    public List<ExQuestion> buildMenuTree(List<ExQuestion> menuList) {
        Map<Integer, ExQuestion> menuMap = new HashMap<>();

        // 将菜单放入Map中,以菜单ID作为键
        for (ExQuestion menu : menuList) {
            menuMap.put(menu.getId(), menu);
        }

        // 遍历菜单列表,将子菜单添加到对应的父菜单的children属性中
        List<ExQuestion> treeMenu = new ArrayList<>();
        for (ExQuestion menu : menuList) {
            Integer parentId = menu.getPid();
            ExQuestion parentMenu = menuMap.get(parentId);
            if (parentMenu == null) {
                // 如果父菜单不存在,则尝试通过pid查找
                parentMenu = menuMap.get(menu.getPid());
            }
            if (parentMenu == null) {
                // 如果仍然找不到父菜单,则将当前菜单视为顶级菜单
                treeMenu.add(menu);
            } else {
                // 找到父菜单,将当前菜单添加到父菜单的children属性中
                if (parentMenu.getChildren() == null) {
                    parentMenu.setChildren(new ArrayList<>());
                }
                parentMenu.getChildren().add(menu);
            }
        }

       // 对顶级菜单 及其子菜单按照 display_order 排序
        sortTreeMenu(treeMenu);

        return treeMenu;
    }

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值