后端树形数据转换(包括不确定根节点的情况)

后端实现树形结构


比如多级菜单,我们需要一个结构可以更好的展示。

我做了一个简单的多级菜单树形结构,使用的是递归的方式,想要多级也是可以的。

从数据库开始展示。

一、数据库设计
表结构需要包含类似pid的字段存储父id

CREATE TABLE `menu` (
  `id` int(11) NOT NULL,
  `pid` int(11) DEFAULT '0',
  `menu_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

设计的表如图
设计的结构如图

*二、Controller层代码和Mapper层代码,我用的是mybatis-plus

Controller层代码和Mapper层代码很简单。

controller:

@RestController
@RequestMapping("/menu")
public class MenuController {

    @Autowired
    private MenuService menuService;

    @PostMapping("/getMenuList")
    public Result getMenuList(){

        List<Map<String, Object>> menuList = menuService.getMenuList();

        return Result.success(menuList);
    }
}

Mapper:

@Mapper
public interface MenuMapper extends BaseMapper<Menu> {
}

三、逻辑放在了实现层

service:

public interface MenuService {


    List<Map<String,Object>> getMenuList();
}

serviceImpl:

@Service
public class MenuServiceImpl implements MenuService {

    @Resource
    private MenuMapper menuMapper;


    @Override
    public List<Map<String, Object>> getMenuList() {
        //从数据库中获取菜单数据
        Wrapper<Menu> wrapper = Wrappers.<Menu>lambdaQuery();
        List<Menu> menus = menuMapper.selectList(wrapper);
        //创建一个集合存放属性数据
        List<Map<String, Object>> menuList = new ArrayList<>();
        //遍历先放入父节点
        for (Menu menu : menus) {
            Map<String, Object> map = new HashMap<>();
            if (menu.getPid() == 0){
                map.put("id",menu.getId());
                map.put("pid",menu.getPid());
                map.put("menuName",menu.getMenuName());
                map.put("children",getChildren(menus, menu.getId()));
                menuList.add(map);
            }
        }
        return menuList;
    }

    /**
     * 使用递归
     *通过id获取子级
     */

    public List<Map<String, Object>> getChildren(List<Menu> data, Integer id){
        //新建结果集
        List<Map<String, Object>> list = new ArrayList<>();
        //非空判断
        if (data == null || data.size() == 0 || id == null) {
            return list;
        }

        //遍历,比较当前id和pid,一样的话说明当前id存在子级
        for (Menu menu : data) {
            Map<String, Object> map = new HashMap<>();
            if (id.equals(menu.getPid())){
                map.put("id", menu.getId());
                map.put("pid", menu.getPid());
                map.put("menuName", menu.getMenuName());
                //递归查询子级
                map.put("children", getChildren(data, menu.getId()));
                list.add(map);
            }
        }
        return list;

    }
}

四、下面是我用postman测试的结果

{
    "code": 0,
    "msg": "成功",
    "data": [
        {
            "children": [
                {
                    "children": [],
                    "pid": 1,
                    "menuName": "菜单1-1",
                    "id": 3
                },
                {
                    "children": [],
                    "pid": 1,
                    "menuName": "菜单1-2",
                    "id": 4
                }
            ],
            "pid": 0,
            "menuName": "菜单1",
            "id": 1
        },
        {
            "children": [
                {
                    "children": [],
                    "pid": 2,
                    "menuName": "菜单2-1",
                    "id": 5
                }
            ],
            "pid": 0,
            "menuName": "菜单2",
            "id": 2
        }
    ]
}

======================================================
我在开发过程中遇到并不确认根节点的情况,我直接把我的业务代码放了上去

@Override
    public List<SysTypeInfoDTO> getDictionaryForTree(SysTypeInfoVo sysTypeInfoVo) {
        //获取全部
//        PageHelper.startPage(sysTypeInfoVo.getPageNum(), sysTypeInfoVo.getPageSize());
        List<SysTypeInfoDTO> sysTypeInfos = sysTypeInfoMapper.selectList(sysTypeInfoVo);

        Set<SysTypeInfoDTO> checkList = new HashSet<>();//1.定义了一个空集合
        
        //实现多级树形结构的查询,但是并不确定根节点,只通过pid和id进行父级和子级的查询
        if (sysTypeInfos!=null){
            for (SysTypeInfoDTO sysTypeInfo : sysTypeInfos) {
                for (SysTypeInfoDTO typeInfo : sysTypeInfos) {
                    if (typeInfo.getParentId().equals(sysTypeInfo.getTypeId())){
                        //递归查询
                        //存入递归完成的对象
                        checkList.add(typeInfo);
                        List<SysTypeInfoDTO> children = getChildren(sysTypeInfos, sysTypeInfo.getTypeId(), checkList);
                        sysTypeInfo.setTypeChildren(children.size()>0?children:null);
                    }
                }

            }
        }
        //直接删除已经存进的子级
        sysTypeInfos.removeAll(checkList);
        return sysTypeInfos.stream().sorted(Comparator.comparing(SysTypeInfoDTO::getSn).reversed()).collect(Collectors.toList());
    }

    /**
     * 使用递归 通过id获取子级
     *
     * @param data      入参集合
     * @param typeId    父级id
     * @param checkList
     * @return 树形集合
     */
    public List<SysTypeInfoDTO> getChildren(List<SysTypeInfoDTO> data, String typeId, Set<SysTypeInfoDTO> checkList) {
        //新建结果集
        List<SysTypeInfoDTO> list = new ArrayList<>();
        //非空判断
        if (data == null || data.size() == 0 || typeId == null) {
            return null;
        }
        //遍历,比较当前typeId和pid,一样的话说明当前id存在子级
        for (SysTypeInfoDTO sysTypeInfo : data) {
            if (typeId.equals(sysTypeInfo.getParentId())) {
                if (checkList != null) {
                //这里也存入
                    checkList.add(sysTypeInfo);
                }
                //递归查询子级
                List<SysTypeInfoDTO> children = getChildren(data, sysTypeInfo.getTypeId(), checkList);
                sysTypeInfo.setTypeChildren(children.size()>0?children:null);
                list.add(sysTypeInfo);
            }
        }
        return list;
    }

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值