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;
}
}