java+mysql递归拼接树形JSON列表

本文介绍了一种将扁平化的目录列表转换成树形JSON数据的方法,并提供了完整的Java实现代码。通过递归的方式构建出多级目录结构,适用于前端展示如国家省市县等选择器。

前言:在做java web项目时,前端控件例如国家-省-市-区-县等树形列表,常常需要多级树形json数据,例如:

[
  {
    "name": "商品目录",
    "pid": "-1",
    "id": "1",
    "children": [
      {
        "name": "日用品",
        "pid": "1",
        "id": "11",
        "children": [
          {
            "name": "洗发水",
            "pid": "11",
            "id": "111",
            "children": [
                {
                    "name": "霸王",
                    "pid": "111",
                    "id": "1111",
                    "children": []
                }
            ]
          }
        ]
      },
      {
        "name": "食品",
        "pid": "1",
        "id": "12",
        "children": []
      }
    ]
  }
]

整体思路分为两步,第一步获取目录及其所有子目录,获取后的列表形式如下:

[
    {"id":"1","pid":"-1","name":"商品目录"},
    {"id":"11","pid":"1","name":"日用品"},
    {"id":"12","pid":"1","name":"食品"},
    {"id":"111","pid":"11","name":"洗发水"},
    {"id":"1111","pid":"111","name":"霸王"}
]

第二步,利用递归思想拼装该数据,拼装方法的工具类如下:

package *.*.*;

import net.sf.json.JSONArray;

import java.util.ArrayList;
import java.util.List;

/**
 * 构造目录JSON树
 * Created by fukang on 2017/5/26 0026.
 */
public class TreeBuilder {

    List<Node> nodes = new ArrayList<>();

    public String buildTree(List<Node> nodes) {

        TreeBuilder treeBuilder = new TreeBuilder(nodes);

        return treeBuilder.buildJSONTree();
    }

    public TreeBuilder() {
    }

    public TreeBuilder(List<Node> nodes) {
        super();
        this.nodes = nodes;
    }

    // 构建JSON树形结构
    public String buildJSONTree() {
        List<Node> nodeTree = buildTree();
        JSONArray jsonArray = JSONArray.fromObject(nodeTree);
        return jsonArray.toString();
    }

    // 构建树形结构
    public List<Node> buildTree() {
        List<Node> treeNodes = new ArrayList<>();
        List<Node> rootNodes = getRootNodes();
        for (Node rootNode : rootNodes) {
            buildChildNodes(rootNode);
            treeNodes.add(rootNode);
        }
        return treeNodes;
    }

    // 递归子节点
    public void buildChildNodes(Node node) {
        List<Node> children = getChildNodes(node);
        if (!children.isEmpty()) {
            for (Node child : children) {
                buildChildNodes(child);
            }
            node.setChildren(children);
        }
    }

    // 获取父节点下所有的子节点
    public List<Node> getChildNodes(Node pnode) {
        List<Node> childNodes = new ArrayList<>();
        for (Node n : nodes) {
            if (pnode.getId().equals(n.getPid())) {
                childNodes.add(n);
            }
        }
        return childNodes;
    }

    // 判断是否为根节点
    public boolean rootNode(Node node) {
        boolean isRootNode = true;
        for (Node n : nodes) {
            if (node.getPid().equals(n.getId())) {
                isRootNode = false;
                break;
            }
        }
        return isRootNode;
    }

    // 获取集合中所有的根节点
    public List<Node> getRootNodes() {
        List<Node> rootNodes = new ArrayList<>();
        for (Node n : nodes) {
            if (rootNode(n)) {
                rootNodes.add(n);
            }
        }
        return rootNodes;
    }

    public static class Node {

        private String id;
        private String pid;
        private String name;
        private List<Node> children;

        public Node() {
        }

        public Node(String id, String pid, String name) {
            super();
            this.id = id;
            this.pid = pid;
            this.name = name;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getPid() {
            return pid;
        }

        public void setPid(String pid) {
            this.pid = pid;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }


        public List<Node> getChildren() {
            return children;
        }

        public void setChildren(List<Node> children) {
            this.children = children;
        }
    }
}

在Controller中的调用方法是:

    @RequestMapping("/bulidJsonTree")
    @ResponseBody
    public String buildJsonTree(HttpServletRequest request) {

        // 获取全部目录节点
        List<Node> nodes = iGoodsDirSvc.getAllDirList();

        // 拼装树形json字符串
        String json = new TreeBuilder().buildTree(nodes);

        return json;
    }

其中iGoodsDirSvc.getAllDirList()方法需要将取到的数据转为Node类型:

String hql = "select id as id,pId as pid,name as name from Directory";

Query query = factory.getCurrentSession().createQuery(hql)
.setResultTransformer(Transformers.aliasToBean(TreeBuilder.Node.class));

return query.list();
### 如何在 MySQL 中拆分由逗号拼接的字符串 在 MySQL 中,如果需要将一个由逗号分割的字符串拆分为多行或多列,可以利用一些内置函数或者通过创建自定义存储过程来实现这一目标。以下是几种常见的方法: #### 方法一:使用 `FIND_IN_SET` 和 `SUBSTRING_INDEX` 可以通过组合使用 `FIND_IN_SET` 函数和 `SUBSTRING_INDEX` 来逐一分割字符串中的每一部分。 ```sql SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a,b,c,d', ',', numbers.n), ',', -1) AS value FROM ( SELECT 1 n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 ) numbers WHERE numbers.n <= LENGTH('a,b,c,d') - LENGTH(REPLACE('a,b,c,d', ',', '')) + 1; ``` 上述查询会返回如下结果[^4]: | value | |-------| | a | | b | | c | | d | 此方法的核心在于生成一组连续的数字(通常称为序列表),并将其用于逐步提取字符串的不同部分。 --- #### 方法二:使用递归 CTE(适用于 MySQL 8.0 及以上版本) 从 MySQL 8.0 开始支持递归公用表表达式 (CTE),这使得处理此类问题更加简洁高效。 ```sql WITH RECURSIVE split_cte AS ( SELECT 'a,b,c,d' AS str, NULL AS part, 0 AS idx UNION ALL SELECT SUBSTRING(str, INSTR(str, ',')+1), IF(INSTR(str, ',')>0, LEFT(str, INSTR(str,',')-1), str), idx + 1 FROM split_cte WHERE str != '' ) SELECT TRIM(part) AS value FROM split_cte WHERE part IS NOT NULL; ``` 该查询同样会产生以下输出: | value | |-------| | a | | b | | c | | d | 这种方法的优点是可以动态适应不同长度的输入字符串,并且无需手动构建辅助数据集。 --- #### 方法三:借助临时表或视图 对于更复杂的情况,可能需要先将原始记录存入一张中间表格中,然后再执行进一步操作。例如,假设存在这样一条记录 `(id=1, col='apple,banana,cherry')` ,我们希望按逗号分开后得到三条独立的结果项,则可采用下面的方式完成转换工作: ```sql CREATE TEMPORARY TABLE temp_split ( id INT PRIMARY KEY AUTO_INCREMENT, orig_id INT, item VARCHAR(255) ); INSERT INTO temp_split(orig_id, item) SELECT t.id, s.value FROM your_table t JOIN JSON_TABLE(CONCAT('["', REPLACE(t.col, ',', '","'), '"]'), '$[*]' COLUMNS(value VARCHAR(255) PATH '$')) s; -- 查询最终结果 SELECT * FROM temp_split ORDER BY orig_id ASC; ``` 这里引入了 `JSON_TABLE()` 功能作为桥梁连接起原字段与新产生的各个片段之间的关系链路[^5]。 --- ### 总结 尽管 MySQL 自身并未提供专门针对字符串切割成行的功能指令,但凭借灵活运用现有工具仍能达成预期效果。具体选择哪种方案取决于实际应用场景以及数据库系统的兼容程度等因素考量。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值