背景:
我们前后端交互可能会涉及到树形结构数据
1,大多数设计,定义树结构基类
package com.yw.framework.tree; import lombok.Data; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** * 功能描述: <结构树> * 〈〉 * * @Author: zl * @Date: 2021/10/15 9:15 */ @Data public class Node { protected String id; protected String parentId; protected String name; protected List<Node> children = new ArrayList<>(); protected String description; protected int rank = 0; }
2,不同父结构数据类型继承即可
@Data public static class AbilityNode extends Node { private Double weight; private List<AbilityQuotaResp> abilityQuotaRespList; }
3,构建工具类
package com.yw.framework.tree; import java.util.ArrayList; import java.util.List; /** * @Author zl * @Description 树形构造处理工具类 * * @Date 2021/6/1 9:12 */ public class BuildTree { /** * 功能描述: <生成树结构> * 〈〉 * * @Param: [T] * @Author: zl * @Date: 2021/6/1 9:10 */ public static List<Node> buildTree(List<? extends Node> nodeList) { List<Node> nodes = new ArrayList<>(); for (Node node : nodeList) { String parentId = node.getParentId(); if (parentId == null || "".equals(parentId)) { nodes.add(node); continue; } for (Node parent : nodeList) { if (parent.getId().equals(parentId)) { List<Node> parentList = parent.getChildren(); if (parentList == null) { parentList = new ArrayList<>(); parentList.add(node); parent.setChildren(parentList); } else { parentList.add(node); } } } } return nodes; } /** * 给树节点设置层级rank标识 * * @param nodes */ public static void setLevel(List<Node> nodes) { for (Node node : nodes) { String parentId = node.getParentId(); if (parentId == null || "".equals(parentId)) { node.setRank(1); dfsLevel(node); } } } /** * 递归遍历节点数 * @param node */ public static void dfsLevel(Node node) { List<Node> children = node.getChildren(); if (children!=null) { for (Node child : children) { child.setRank(node.getRank() + 1); dfsLevel(child); } } } /** * 获取树的最大层级 * * @param nodes * @return */ public static int maxLevel(List<Node> nodes,int maxlevel) { for (Node node : nodes) { maxlevel = Math.max(node.getRank(), maxlevel); if (node.getChildren()!=null) { return maxLevel(node.getChildren(), maxlevel); } } return maxlevel; } /** * 获取树的某一层级所有节点 * * @param nodes * @param level * @return */ public static List<Node> getLevelNode(List<Node> nodes, int level, List<Node> nodeList) { for (Node node : nodes) { if (node.getRank() == level) { nodeList.add(node); } if (node.getChildren()!=null) { getLevelNode(node.getChildren(), level, nodeList); } } return nodeList; } /** * 获取树的所有叶子节点 * * @param nodes * @return */ public static List<Node> getLeafNode(List<? extends Node> nodes, List<Node> leafNode) { for (Node node : nodes) { if (node.getChildren() == null || node.getChildren().size() == 0) { leafNode.add(node); } else { getLeafNode(node.getChildren(), leafNode); } } return leafNode; } /** * 删除给定的叶子节点 * @param nodes * @param ids * @param deleteSize * @return */ public static int deleteLeafNode(List<Node> nodes, String[] ids, int deleteSize) { boolean b = nodes.removeIf(node -> { if ((node.getParentId() == null || "".equals(node.getParentId())) && (node.getChildren() == null || node.getChildren().size() == 0)) { boolean isDelete = true; for (int i = 0; i < ids.length; i++) { if (ids[i].equals(node.getId())) { isDelete = false; break; } } return isDelete; } return false; }); if (b) { deleteSize++; } for (Node node : nodes) { if (node.getChildren() == null || node.getChildren().size() == 0) { boolean isDelete = true; for (int i = 0; i < ids.length; i++) { if (ids[i].equals(node.getId())) { isDelete = false; } } if (isDelete) { deleteSize++; for (Node parent : nodes) { if (parent.getId().equals(node.getParentId())) { parent.getChildren().remove(node); break; } } } } else { return deleteLeafNode(node.getChildren(), ids, deleteSize); } } return deleteSize; } }
4,这样作为后端返回给前端设计没有问题
5,但是,如果是接收前端树形结构就会出现问题,接收的树结构的子节点数据都没有继承类中定义的数据
例如这样一个结构数据:
"abilityNodeList": [ { "id": "1", "elementId": "能力", "parentId": "", "name": "侦查能力", "children": [ { "id": "5d0c25bfb00f4120bb56ecee1f16a20b","parentId": "1", "name": "111", "children": [], "description": "111", "rank": 0, "weight": 0.2, "abilityQuotaRespList": [] }, { "id": "19859ac711964779aabf453fae7aa890","parentId": "1", "name": "222", "children": [], "description": "", "rank": 0, "weight": 0.2, "abilityQuotaRespList": [] } ], "description": "侦查能力", "rank": 0, "weight": 0.2, "abilityQuotaRespList": [ { "id": "6", "name": "能力指标6", "weight": 0.8, "contribution": 0 }, { "id": "7", "name": "能力指标7", "weight": 0.6, "contribution": 0 } ] }, { "id": "3","parentId": "", "name": "预警能力", "children": [], "description": "预警能力", "rank": 0, "weight": 0.2, "abilityQuotaRespList": [] }, { "id": "2","parentId": "", "name": "通信能力", "children": [], "description": "通信能力", "rank": 0, "weight": 0.2, "abilityQuotaRespList": [ { "id": "3", "name": "海上通信", "weight": 0.4, "contribution": 0.1 }, { "id": "4", "name": "地面通信", "weight": 0.4, "contribution": 0.1 } ] } ]
请求过来之后,除了根节点数据,所有子节点都没有weight和abilityQuotaRespList属性以及数据子节点默认还是基类(Node)类型
6,最后,请求数据 树形结构类型不能用继承
可这样直接设计,即定制化设计:
package com.yw.module.abilitycontribution.resp; import com.yw.module.core.InputOutcomeData.SystemAbilityInputNodeData; import lombok.Data; import java.util.ArrayList; import java.util.List; /** * @Author zl * @Description * @Date 2021/10/15 9:16 */ @Data public class AbilityNode { protected String id; protected String parentId; protected String name; protected List<AbilityNode> children = new ArrayList<>(); protected int rank = 0; private Double weight; private List<AbilityQuotaResp> abilityQuotaRespList; @Data public static class AbilityQuotaResp{ private String id; private String name; } }