背景

最近公司有个需求,要自研接口平台,将公司接口对接到接口平台,统一进行管理,其中,新增接口的时候新增参数,参数是一个树形结构,需要先解析出参数,然后将参数的树形结构按层级生成id,和pid, 再转换成数组,获取接口详情的时候需要将这一过程返过来,将参数数组转换成树

树结构

(id, pid)
              (1,0)
                    - (2, 1)
                    - (3, 1)
                          - (4, 3)

              (5,0)
                    - (7,5)
              (8,0)
                    - (9,8)
              (10,0)

代码

/**
 * @author: lpy
 * @Date: 2023/01/07
 */
@Data
@Accessors(chain = true)
public class TreeNode {
    /**
     * id
     */
    private Long id;

    /**
     * 父id
     */
    private Long pid;

    /**
     * 每个节点路径
     */
    private String path;

    private List<TreeNode> params;
}

完整代码

public class TreesUtil {
    private static ArrayList<TreeNode> paramArr;
    private static Stack<String> stack;

    static {
        stack = new Stack<>();
    }

    /**
     * 将数组转换成树
     *
     * @param treeList 数组
     * @param parentId parentId
     * @return list
     */
    public static List<TreeNode> toTree(List<TreeNode> treeList, Long parentId) {
        List<TreeNode> list = treeList.stream()
                .filter(parent -> parent.getPid().equals(parentId))
                .map(child -> {
                    child.setParams(toTree(treeList, child.getId()));
                    return child;
                }).collect(Collectors.toList());
        return list;
    }

    /**
     * 为树状结构生成id 和 path(父节点到子节点路径)
     *
     * @param list 树
     * @param pid  pid
     * @return List
     */
    public List<TreeNode> generateTreePid(List<TreeNode> list, Long pid) {
        for (TreeNode param : list) {
            Long id = IdUtil.getSnowflakeNextId();
            param.setId(id);
            String pidPath = pid == 0L ? "/" : stack.isEmpty() ? "" : stack.peek() + "/";
            if (CollectionUtils.isNotEmpty(param.getParams())) {
                // 下面有节点要回溯
                stack.push(pidPath + id);
                generateTreePid(param.getParams(), id);
            } else {
                String temp = (stack.isEmpty() ? "" : stack.peek()) + "/" + id;
                stack.push(temp);
            }
            param.setPath(stack.pop());
            param.setPid(pid);
        }
        return list;
    }


    /**
     * 将树结构转换成数组
     *
     * @param list 树
     * @return List<>
     */
    public List<TreeNode> treeToList(List<TreeNode> list) {
        paramArr = new ArrayList<>();
        this.addToArr(list);
        return paramArr;
    }

    /**
     * 树结构转换成数组
     *
     * @param list list
     * @return List<TreeNode>
     */
    private List<TreeNode> addToArr(List<TreeNode> list) {
        for (TreeNode apiParam : list) {
            if (CollectionUtils.isNotEmpty(apiParam.getParams())) {
                addToArr(apiParam.getParams());
            }
            apiParam.setParams(new ArrayList<>());
            paramArr.add(apiParam);
        }
        return list;
    }
}

其中为树生成path想了挺久的,这个不像是二叉树,有左子节点,右子节点,有一个根节点,这个有好多根节点和子节点,

最终采用的方法是递归加回溯,其中回溯我才用了java的栈,弹栈来实现

不采用回溯的话,一开始的节点path是没有问题的,但是下面的节点path会带有起初节点的子节点和父节点路径,

测试代码

public static void main(String[] args) {
        ArrayList<TreeNode> list = new ArrayList<>();
        list.add(new TreeNode().setId(1L).setPid(0L));
        list.add(new TreeNode().setId(2L).setPid(1L));
        list.add(new TreeNode().setId(3L).setPid(1L));
        list.add(new TreeNode().setId(4L).setPid(3L));
        list.add(new TreeNode().setId(5L).setPid(0L));
        list.add(new TreeNode().setId(7L).setPid(5L));
        list.add(new TreeNode().setId(8L).setPid(0L));
        list.add(new TreeNode().setId(9L).setPid(8L));
        list.add(new TreeNode().setId(10L).setPid(0L));

        ArrayList<TreeNode> listDto = new ArrayList<>();
        JSONArray objects = JSON.parseArray(
                "[{\"id\":1,\"params\":[{\"id\":2,\"params\":[],\"pid\":1},{\"id\":3,\"params\":[{\"id\":4,\"params\":[],\"pid\":3}],\"pid\":1}],\"pid\":0},{\"id\":5,\"params\":[{\"id\":7,\"params\":[],\"pid\":5}],\"pid\":0},{\"id\":8,\"params\":[{\"id\":9,\"params\":[],\"pid\":8}],\"pid\":0}]\n"
        );

        for (Object object : objects) {
            TreeNode map = BeanConvertorUtils.map(object, TreeNode.class);
            listDto.add(map);
        }

        List<TreeNode> nodeVOList = toTree(list, 0L);

        System.out.println(JSON.toJSONString(nodeVOList));

        TreesUtil tree = new TreesUtil();
        List<TreeNode> TreeNodeS = tree.generateTreePid(listDto, 0L);
        System.out.println(JSON.toJSONString(TreeNodeS));

        List<TreeNode> TreeNodeS1 = tree.treeToList(TreeNodeS);
        System.out.println(JSON.toJSONString(TreeNodeS1));
        /**
         * [{"apiParamId":1,"fieldType":1,"params":[{"apiParamId":2,"fieldType":2,"params":[],"parentId":1,"remark":"21"},{"apiParamId":3,"fieldType":3,"params":[{"apiParamId":4,"fieldType":4,"params":[],"parentId":3,"remark":"43"}],"parentId":1,"remark":"31"}],"parentId":0,"remark":"1, 0"},{"apiParamId":5,"fieldType":5,"params":[{"apiParamId":7,"fieldType":6,"params":[],"parentId":5,"remark":"75"}],"parentId":0,"remark":"50"},{"apiParamId":8,"fieldType":8,"params":[],"parentId":0,"remark":"80"}]
         *
         *
         * [{"apiParamId":1607261486112108546,"fieldType":1,"params":[{"apiParamId":1607261486112108547,"fieldType":2,"params":[],"parentId":1607261486112108546,"remark":"21"},{"apiParamId":1607261486112108548,"fieldType":3,"params":[{"apiParamId":1607261486112108549,"fieldType":4,"params":[],"parentId":1607261486112108548,"remark":"43"}],"parentId":1607261486112108546,"remark":"31"}],"parentId":0,"remark":"1, 0"},{"apiParamId":1607261486112108550,"fieldType":5,"params":[{"apiParamId":1607261486112108551,"fieldType":6,"params":[],"parentId":1607261486112108550,"remark":"75"}],"parentId":0,"remark":"50"},{"apiParamId":1607261486112108552,"fieldType":8,"params":[],"parentId":0,"remark":"80"}]
         */
    }

补充

查看json结构树形结构

分类: java

0 条评论

发表评论

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用*标注

站点统计

  • 文章总数:304 篇
  • 分类总数:19 个
  • 标签总数:189 个
  • 运行天数:864 天
  • 访问总数:475044 人次
ICP备案号: 辽ICP备20003309号