package com.viewhigh.bi.service.helper; import com.viewhigh.bi.common.utils.BasicUtils; import com.viewhigh.bi.common.utils.ObjectUtil; import com.viewhigh.bi.model.business.category.Tree; import com.viewhigh.bi.model.metadata.Category; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by zzq on 2017/7/28. */ @Component public class CategoryConversion { /** * 构建树形结构时,取出不同模块的节点 * * @param modelName * @return */ public static PropMapper buildPropMapper(final String modelName) { return new CategoryConversion.PropMapper<Map<String, String>>() { @Override public String getId(Map<String, String> item) { return item.get(modelName + "$id"); } @Override public String getName(Map<String, String> item) { return item.get(modelName + "$name"); } @Override public String getCode(Map<String, String> item) { return item.get(modelName + "$code"); } @Override public String getCategoryId(Map<String, String> item) { return item.get(modelName + "$category_id");//chart_model } }; } /** * @param categoryList 仅仅是主题分类和实际模型的所属关系集合,包括分类信息,并不包括具体数据信息 * @param modelDetail 如分析模型,图表模型等能够属于主题分类的详细内容,加到对应的树节点当中 * @param categoryRoot 带有parent_id平铺分类的根节点 * @param treeRoot 转成树结构的根节点 * @param treeRootList 当执行该方法时在treeRootList中包含treeRoot * @param title 按照名称过滤 * @return */ public Tree categoryAndModel2Tree(List<Category> categoryList, Map<String, Object> modelDetail, Category categoryRoot, Tree treeRoot, List<Tree> treeRootList, String title) { if (categoryList == null || categoryList.size() == 0 || categoryRoot == null) return treeRoot; Category category; Object modelMap; List<Category> treeListChildrenTmp; List<Tree> treeArrayList; for (int i = 0; i < categoryList.size(); i++) { category = categoryList.get(i); if (category.getParent_id().equals(categoryRoot.getId())) { Tree tree = new Tree(); tree.setScore(category.getOrder_num()); tree.setDesc(category.getRemark()); String name = category.getName(); if (StringUtils.isNotBlank(title) && (name.toLowerCase().contains(title.toLowerCase()) || treeRootListIncludeTitle(treeRootList, title)) ) {//如果当前子节点被过滤出来则父节点也需要保留 for (Tree item : treeRootList) item.setFilter(true); tree.setFilter(true); } tree.setTitle(category.getName()); String modelId = category.getId(); tree.setKey(modelId); if (!category.isCategory() && modelDetail != null && modelDetail.containsKey(modelId)) { modelMap = modelDetail.get(modelId); tree.setDetail(modelMap); } if (categoryRoot.getChildren() == null) { treeListChildrenTmp = new ArrayList(); treeListChildrenTmp.add(category); categoryRoot.setChildren(treeListChildrenTmp); treeArrayList = new ArrayList(); treeArrayList.add(tree); treeRoot.setChildren(treeArrayList); } else { categoryRoot.getChildren().add(category); treeRoot.getChildren().add(tree); } categoryList.remove(i); i--;//删除已经确定节点的元素,减少时间复杂度 } } List<Category> categoryListChildren = categoryRoot.getChildren(); if (categoryListChildren == null) return treeRoot; List<Tree> treeListChildren = treeRoot.getChildren(); if (treeListChildren == null) return treeRoot; for (int i = 0; i < categoryListChildren.size(); i++) { Tree currTree = treeListChildren.get(i); List<Tree> treeRootListNew = null; if (StringUtils.isNotBlank(title)) { treeRootListNew = new ArrayList<>();//如果不为子节点的话,将所有父级存储并记录,如果子节点为保留状态所有父节点均设置为保留状态 for (Tree item : treeRootList) treeRootListNew.add(item); treeRootListNew.add(currTree); } categoryAndModel2Tree(categoryList, modelDetail, categoryListChildren.get(i), currTree, treeRootListNew, title); } return treeRoot; } private boolean treeRootListIncludeTitle(List<Tree> treeRootList, String title) { for (Tree item : treeRootList) { String name = item.getTitle(); if (name.contains(title)) { return true; } } return false; } public <Bean> Tree build(List<Category> categoryList, List<Bean> modelData, PropMapper<Bean> propMapper) { return build(categoryList, modelData, propMapper, null); } /** * 根据分类元数据,生成分类树的结构 * * @param categoryList * @param modelData * @param propMapper * @param title 用来进行对title的模糊匹配 * @param <Bean> * @return */ public <Bean> Tree build(List<Category> categoryList, List<Bean> modelData, PropMapper<Bean> propMapper, String title) { if (categoryList == null || categoryList.size() == 0) return null; //深copy对象categoryList不改变原有对象,防止多线程使用冲突 List<Category> categoryListCopy = ObjectUtil.deepCopy(categoryList); //0.找到根元素,并从完整集合中删除,减少没有必要的遍历 Category categoryRoot = null;//treeList.remove(0); int indexRoot = 0; for (int i = categoryListCopy.size() - 1; i > -1; i--) { categoryRoot = categoryListCopy.get(i); indexRoot = i; if (StringUtils.isBlank(categoryRoot.getParent_id())) break; } categoryListCopy.remove(indexRoot); //1.构建根级别的树节点用于返回,子节点直接在其中累加 Tree treeRoot = new Tree(); treeRoot.setScore(categoryRoot.getOrder_num()); treeRoot.setKey(categoryRoot.getId()); String name = categoryRoot.getName(); treeRoot.setFilter(true);//根节点始终保留 treeRoot.setTitle(name); treeRoot.setDesc(categoryRoot.getRemark()); Map<String, Object> modelDataMap = null; if (propMapper != null && modelData != null) { //2.将具体模型的list转换成map,用于将模型具体信息递归添加到树对应的位置 modelDataMap = new HashMap(); Category categoryTmp; for (Bean item : modelData) {//一次遍历将list转换为带有id的map modelDataMap.put(propMapper.getId(item), item); //3.将具体模型信息与分类信息合并 categoryTmp = new Category(); categoryTmp.setId(propMapper.getId(item)); categoryTmp.setName(propMapper.getName(item)); categoryTmp.setCode(propMapper.getCode(item)); categoryTmp.setParent_id(propMapper.getCategoryId(item)); categoryTmp.setCategory(false);//标志不是非分类信息实体,仅仅将属性映射成该类型 categoryListCopy.add(categoryTmp); } } List<Tree> treeRootList = null; if (StringUtils.isNotBlank(title)) { treeRootList = new ArrayList<>(); treeRootList.add(treeRoot); } Tree result = categoryAndModel2Tree(categoryListCopy, modelDataMap, categoryRoot, treeRoot, treeRootList, title); if (StringUtils.isNotBlank(title)) { if (!result.isFilter()) return null; result = filterTreeNode(result); } return result; } private Tree filterTreeNode(Tree result) { List<Tree> treeList = result.getChildren(); if (BasicUtils.isEmpty(treeList)) return null; for (int i = 0; i < treeList.size(); i++) { Tree currTree = treeList.get(i); if (currTree.isFilter()) { filterTreeNode(currTree); } else { treeList.remove(i); i--; } } return result; } public interface PropMapper<Bean> { String getId(Bean item); String getName(Bean item); String getCode(Bean item); String getCategoryId(Bean item); } }
package com.viewhigh.bi.model.metadata; import java.util.List; /** * Created by zzq on 2017/6/28. */ public class Category extends BasicModelMetaData { private String parent_id; private List<Category> children; //用于判断是否为分类主题标识,模型合并时用该属性做区分 private boolean isCategory = true; private String order_num; public String getOrder_num() { return order_num; } public void setOrder_num(String order_num) { this.order_num = order_num; } public boolean isCategory() { return isCategory; } public void setCategory(boolean category) { isCategory = category; } public List<Category> getChildren() { return children; } public void setChildren(List<Category> children) { this.children = children; } public String getParent_id() { return parent_id; } public void setParent_id(String parent_id) { this.parent_id = parent_id; } }
package com.viewhigh.bi.model.business.category; import java.io.Serializable; import java.util.List; /** * Created by zzq on 2017/7/27. */ public class Tree implements Serializable { private String key; private String title; private String desc; private Object detail;//没有 private List<Tree> children; private String score; private boolean filter = false; public boolean isFilter() { return filter; } public void setFilter(boolean filter) { this.filter = filter; } public String getScore() { return score; } public void setScore(String score) { this.score = score; } public List<Tree> getChildren() { return children; } public void setChildren(List<Tree> children) { this.children = children; } public Object getDetail() { return detail; } public void setDetail(Object detail) { this.detail = detail; } public Tree() { } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }