【四二学堂】树结构表,列表转换成树状关系的工具类

28 篇文章 0 订阅

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值