项目中经常会有我们需要按照前端提供的接口文档返回数据
其中树型结构很常见,除了ztree、jstree等树,还有一种常用的森林树:
森林树的实现比较繁琐,如果和前端开发沟通能使用id、pid来实现是最好不过的,可以大大减少后台逻辑
//我们查询出来的list数据中一定要有id和pid来指定对应关系
@ResponseBody
@RequestMapping("treelist")
@ApiOperation(notes = "treelist", httpMethod = "GET", value = "树结构的对比分析接口")
public Object treelist(HttpServletRequest request, HttpServletResponse response) {
try {
//查询出来的数组
List<ZtAnalysisConfig> findAllList = ztAnalysisConfigService.findAllListByZtid(ztid);
List<ZtAnaTreeNode> resultList = new ArrayList<>();
for (ZtAnalysisConfig ztAnalysisConfig : findAllList) {
ZtAnaTreeNode node = new ZtAnaTreeNode();
//这里写业务逻辑
resultList.add(node);
}
List<ZtAnaTreeNode> tns = ForestNodeMerger.merge(resultList);
JSONArray jsonArray = JSONArray.fromObject(tns);
return jsonArray;
} catch (Exception e) {
e.printStackTrace();
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("success", false);
hashMap.put("message", "请正确配置专题分析配置");
return hashMap;
}
}
//以下是树结构相关的内部类
/**
* @ClassName: ZtAnaTreeNode
* @Description: TODO(这里用一句话描述这个类的作用)
* @author Administrator
* @date 2020年3月23日
*
*/
public static class ZtAnaTreeNode {
private String id; // 分析配置的id
private String pid; // 分析配置项pid
private String name; //分析配置的名称
private String tcid; //图层id
private String tcurl; //图层地址
private String tcmc; // 图层名称
private String type; //图层类型
private String servertype; //服务类型
private String dictstr; //关联的字典表
private List<Map<String,Object>> showfield; //显示字段
private List<Map<String,Object>> outtableheader; //外层表头
private String classfyfield; //分类字段
private String countfield; //统计字段
private String defaultunit; //默认显示单位
private String shownumber; // 显示位数
private String relateid; //关联id
public List<ZtAnaTreeNode> children = new ArrayList<ZtAnaTreeNode>();
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 String getTcid() {
return tcid;
}
public void setTcid(String tcid) {
this.tcid = tcid;
}
public String getTcurl() {
return tcurl;
}
public void setTcurl(String tcurl) {
this.tcurl = tcurl;
}
public String getTcmc() {
return tcmc;
}
public void setTcmc(String tcmc) {
this.tcmc = tcmc;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getServertype() {
return servertype;
}
public void setServertype(String servertype) {
this.servertype = servertype;
}
public String getDictstr() {
return dictstr;
}
public void setDictstr(String dictstr) {
this.dictstr = dictstr;
}
public List<Map<String,Object>> getOuttableheader() {
return outtableheader;
}
public void setOuttableheader(List<Map<String,Object>> outtableheader) {
this.outtableheader = outtableheader;
}
public List<Map<String, Object>> getShowfield() {
return showfield;
}
public void setShowfield(List<Map<String, Object>> showfield) {
this.showfield = showfield;
}
public String getClassfyfield() {
return classfyfield;
}
public void setClassfyfield(String classfyfield) {
this.classfyfield = classfyfield;
}
public String getCountfield() {
return countfield;
}
public void setCountfield(String countfield) {
this.countfield = countfield;
}
public String getDefaultunit() {
return defaultunit;
}
public void setDefaultunit(String defaultunit) {
this.defaultunit = defaultunit;
}
public String getShownumber() {
return shownumber;
}
public void setShownumber(String shownumber) {
this.shownumber = shownumber;
}
public String getRelateid() {
return relateid;
}
public void setRelateid(String relateid) {
this.relateid = relateid;
}
public List<ZtAnaTreeNode> getChildren() {
return children;
}
public void setChildren(List<ZtAnaTreeNode> children) {
this.children = children;
}
}
public static class ForestNodeManager {
private List<ZtAnaTreeNode> list;// 森林的所有节点
public ForestNodeManager(ZtAnaTreeNode[] items) {
list = new ArrayList<ZtAnaTreeNode>();
for (ZtAnaTreeNode treeNode : items) {
list.add(treeNode);
}
}
public ForestNodeManager(List<ZtAnaTreeNode> items) {
list = items;
}
/**
* 根据节点ID获取一个节点
*
* @param id
* 节点ID
* @return 对应的节点对象
*/
public ZtAnaTreeNode getTreeNodeAT(String id) {
for (ZtAnaTreeNode treeNode : list) {
if (id.equals(treeNode.getId()))
return treeNode;
}
return null;
}
/**
* 获取树的根节点【一个森林对应多颗树】
*
* @return 树的根节点集合
*/
public List<ZtAnaTreeNode> getRoot() {
List<ZtAnaTreeNode> roots = new ArrayList<ZtAnaTreeNode>();
for (ZtAnaTreeNode treeNode : list) {
if ("0".equals(treeNode.getPid()))
roots.add(treeNode);
}
return roots;
}
}
public static class ForestNodeMerger {/**
* 将节点数组归并为一个森林(多棵树)(填充节点的children域)
* 时间复杂度为O(n^2)
* @param items 节点域
* @return 多棵树的根节点集合
*/
public static List<ZtAnaTreeNode> merge(ZtAnaTreeNode[] items){
ForestNodeManager forestNodeManager = new ForestNodeManager(items);
for (ZtAnaTreeNode treeNode : items) {
if(!"0".equals(treeNode.getPid())){
ZtAnaTreeNode t = forestNodeManager.getTreeNodeAT(treeNode.getPid());
t.getChildren().add(treeNode);
}
}
return forestNodeManager.getRoot();
}
/**
* 将节点数组归并为一个森林(多棵树)(填充节点的children域)
* 时间复杂度为O(n^2)
* @param items 节点域
* @return 多棵树的根节点集合
*/
public static List<ZtAnaTreeNode> merge(List<ZtAnaTreeNode> items){
ForestNodeManager forestNodeManager = new ForestNodeManager(items);
for (ZtAnaTreeNode treeNode : items) {
if(!"0".equals(treeNode.getPid())){
ZtAnaTreeNode t = forestNodeManager.getTreeNodeAT(treeNode.getPid());
t.getChildren().add(treeNode);
}
}
return forestNodeManager.getRoot();
}
}
返回结果:[{
id: xxx,
pid: xxx,
children: [{
......
}]
}]
以上的返回结果存在一个问题:没有子节点的数据会有children为[]的情况,我们可以通过后台的递归去消除,也可以在前端递归消除:
function deleteChildren(arr) {
let childs = arr
for (let i = childs.length; i--; i > 0) {
if (childs[i].children) {
if (childs[i].children.length) {
this.deleteChildren(childs[i].children)
} else {
delete childs[i].children
}
}
}
return arr
}