樹結構表,列表轉換成樹狀關係的工具類
阿新 • • 發佈:2018-12-20
controller
@RequestMapping(value = "deviceinfo") @JSON(type = InfoTree.class, filter = "createDate,updateDate,pageNo,pageSize,parentIds") public List treeData2(@RequestParam(required=false) String extId, HttpServletResponse response) { List<InfoTree> list = testTreeService.findLists(new InfoTree()); return list; }
service
public List<InfoTree> findLists(InfoTree testTree) { List<InfoTree> list = super.findList(testTree); List<InfoTree> servicePlaces = TreeSupportEntity.list2tree(list, InfoTree::setChildList, (Predicate<InfoTree>) servicePlace -> // parentId為空或者為-1的選單則認為是根選單 StringUtils.isEmpty(servicePlace.getParentId()) || servicePlace.getParentId().equals("-1") || servicePlace.getParentId().equals("0")); return servicePlaces; }
xml
<select id="findList" resultType="com.hollysmart.admin.modules.info.entity.InfoTree"> SELECT <include refid="testTreeColumns"/> FROM test_tree_data a <include refid="testTreeJoins"/> <where> a.del_flag = #{DEL_FLAG_NORMAL} <if test="parent != null and parent.id != null and parent.id != ''"> AND a.parent_id = #{parent.id} </if> <if test="parentIds != null and parentIds != ''"> AND a.parent_ids LIKE <if test="dbName == 'oracle'">'%'||#{parentIds}||'%'</if> <if test="dbName == 'mssql'">'%'+#{parentIds}+'%'</if> <if test="dbName == 'mysql'">concat('%',#{parentIds},'%')</if> </if> <if test="name != null and name != ''"> AND a.name LIKE <if test="dbName == 'oracle'">'%'||#{name}||'%'</if> <if test="dbName == 'mssql'">'%'+#{name}+'%'</if> <if test="dbName == 'mysql'">concat('%',#{name},'%')</if> </if> </where> ORDER BY a.sort ASC </select>
實體類
public class InfoTree extends TreeEntity<InfoTree> implements TreeSupportEntity {
private static final long serialVersionUID = 1L;
private InfoTree parent; // 父級編號
private String parentIds; // 所有父級編號
private String name; // 名稱
private Integer sort; // 排序
private List<InfoTree> childList = Lists.newArrayList();
//getter/setter
}
樹狀工具實體類
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 樹形資料構造
*
* @param <PK> 實體主鍵型別
*/
public interface TreeSupportEntity<PK> {
PK getId();
PK getParentId();
/**
* 集合轉為樹形結構,返回根節點集合
*
* @param dataList 需要轉換的集合
* @param childConsumer 設定子節點回調
* @param <N> 樹節點型別
* @param <PK> 主鍵型別
* @return 樹形結構集合
*/
static <N extends TreeSupportEntity<PK>, PK> List<N> list2tree(Collection<N> dataList, BiConsumer<N, List<N>> childConsumer) {
return list2tree(dataList, childConsumer, (Function<TreeHelper<N, PK>, Predicate<N>>) predicate -> node -> node == null || predicate.getNode(node.getParentId()) == null);
}
/**
* 列表結構轉為樹結構,並返回根節點集合
*
* @param dataList 資料集合
* @param childConsumer 子節點消費介面,用於設定子節點
* @param rootNodePredicate 判斷是否為跟節點的函式
* @param <N> 元素型別
* @param <PK> 主鍵型別
* @return 根節點集合
*/
static <N extends TreeSupportEntity<PK>, PK> List<N> list2tree(Collection<N> dataList,
BiConsumer<N, List<N>> childConsumer,
Predicate<N> rootNodePredicate) {
return list2tree(dataList, childConsumer, (Function<TreeHelper<N, PK>, Predicate<N>>) predicate -> rootNodePredicate);
}
/**
* 列表結構轉為樹結構,並返回根節點集合
*
* @param dataList 資料集合
* @param childConsumer 子節點消費介面,用於設定子節點
* @param predicateFunction 根節點判斷函式,傳入helper,獲取一個判斷是否為跟節點的函式
* @param <N> 元素型別
* @param <PK> 主鍵型別
* @return 根節點集合
*/
static <N extends TreeSupportEntity<PK>, PK> List<N> list2tree(final Collection<N> dataList,
final BiConsumer<N, List<N>> childConsumer,
final Function<TreeHelper<N, PK>, Predicate<N>> predicateFunction) {
Objects.requireNonNull(dataList, "source list can not be null");
Objects.requireNonNull(childConsumer, "child consumer can not be null");
Objects.requireNonNull(predicateFunction, "root predicate function can not be null");
Supplier<Stream<N>> streamSupplier = () -> dataList.size() < 1000 ? dataList.stream() : dataList.parallelStream();
// id,node
Map<PK, N> cache = new HashMap<>();
// parentId,children
Map<PK, List<N>> treeCache = streamSupplier.get()
.peek(node -> cache.put(node.getId(), node))
.collect(Collectors.groupingBy(TreeSupportEntity::getParentId));
Predicate<N> rootNodePredicate = predicateFunction.apply(new TreeHelper<N, PK>() {
@Override
public List<N> getChildren(PK parentId) {
return treeCache.get(parentId);
}
@Override
public N getNode(PK id) {
return cache.get(id);
}
});
return streamSupplier.get()
//設定每個節點的子節點
.peek(node -> childConsumer.accept(node, treeCache.get(node.getId())))
//獲取根節點
.filter(rootNodePredicate)
.collect(Collectors.toList());
}
/**
* 樹結構Helper
*
* @param <T> 節點型別
* @param <PK> 主鍵型別
*/
interface TreeHelper<T, PK> {
/**
* 根據主鍵獲取子節點
*
* @param parentId 節點ID
* @return 子節點集合
*/
List<T> getChildren(PK parentId);
/**
* 根據id獲取節點
*
* @param id 節點ID
* @return 節點
*/
T getNode(PK id);
}
}