All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.fartherp.framework.tree.service.BaseTreeableServiceImpl Maven / Gradle / Ivy

/*
 * Copyright (c) 2017. CK. All rights reserved.
 */

package com.github.fartherp.framework.tree.service;


import com.github.fartherp.framework.database.mybatis.plugin.search.enums.SearchOperator;
import com.github.fartherp.framework.database.mybatis.plugin.search.filter.CustomConditionFactory;
import com.github.fartherp.framework.database.mybatis.plugin.search.filter.SearchFilter;
import com.github.fartherp.framework.database.mybatis.plugin.search.vo.Searchable;
import com.github.fartherp.framework.database.service.impl.ExtendGenericSqlMapServiceImpl;
import com.github.fartherp.framework.tree.bo.Treeable;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.collections.ListUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * Created by framework-tree.
 * Auth: hyssop
 * Date: 2016/9/7
 */
public abstract class BaseTreeableServiceImpl, ID extends Serializable>
        extends ExtendGenericSqlMapServiceImpl {

    public T save(T m) {
        if (m.getWeight() == null) {
            m.setWeight(nextWeight(m.getParentId()));
        }
        saveOrUpdate(m);
        return m;
    }

    @Transactional
    public void deleteSelfAndChild(T m) {
        List ms = getDao().selectAll();
        List results = new ArrayList();
        for (T t : ms) {
            if (t.getParentId().equals(m.getId())) {
                getDao().deleteByPrimaryKey((ID) t.getId());
            }
        }
        getDao().deleteByPrimaryKey((ID) m.getId());
    }

    public void deleteSelfAndChild(List mList) {
        for (T m : mList) {
            deleteSelfAndChild(m);
        }
    }

    public void appendChild(T parent, T child) {
        child.setParentId((ID) parent.getId());
        child.setParentIds(parent.makeSelfAsNewParentIds());
        child.setWeight(nextWeight((ID) parent.getId()));
        save(child);
    }

    public int nextWeight(ID id) {
        return getDao().selectByPrimaryKey(id).getWeight();
    }

    /**
     * 移动节点
     * 根节点不能移动
     *
     * @param source   源节点
     * @param target   目标节点
     * @param moveType 位置
     */
    public void move(T source, T target, String moveType) {
        if (source == null || target == null || source.isRoot()) { //根节点不能移动
            return;
        }

        //如果是相邻的兄弟 直接交换weight即可
        boolean isSibling = source.getParentId().equals(target.getParentId());
        boolean isNextOrPrevMoveType = "next".equals(moveType) || "prev".equals(moveType);
        if (isSibling && isNextOrPrevMoveType && Math.abs(source.getWeight() - target.getWeight()) == 1) {
            //无需移动
            if ("next".equals(moveType) && source.getWeight() > target.getWeight()) {
                return;
            }
            if ("prev".equals(moveType) && source.getWeight() < target.getWeight()) {
                return;
            }
            int sourceWeight = source.getWeight();
            source.setWeight(target.getWeight());
            target.setWeight(sourceWeight);
            return;
        }

        //移动到目标节点之后
        if ("next".equals(moveType)) {
            List siblings = findSelfAndNextSiblings(target.getParentIds(), target.getWeight());
            siblings.remove(0);//把自己移除

            if (siblings.size() == 0) { //如果没有兄弟了 则直接把源的设置为目标即可
                int nextWeight = nextWeight(target.getParentId());
                updateSelftAndChild(source, target.getParentId(), target.getParentIds(), nextWeight);
                return;
            } else {
                moveType = "prev";
                target = siblings.get(0); //否则,相当于插入到实际目标节点下一个节点之前
            }
        }

        //移动到目标节点之前
        if ("prev".equals(moveType)) {

            List siblings = findSelfAndNextSiblings(target.getParentIds(), target.getWeight());
            //兄弟节点中包含源节点
            if (siblings.contains(source)) {
                // 1 2 [3 source] 4
                siblings = siblings.subList(0, siblings.indexOf(source) + 1);
                int firstWeight = siblings.get(0).getWeight();
                for (int i = 0; i < siblings.size() - 1; i++) {
                    siblings.get(i).setWeight(siblings.get(i + 1).getWeight());
                }
                siblings.get(siblings.size() - 1).setWeight(firstWeight);
            } else {
                // 1 2 3 4  [5 new]
                int nextWeight = nextWeight(target.getParentId());
                int firstWeight = siblings.get(0).getWeight();
                for (int i = 0; i < siblings.size() - 1; i++) {
                    siblings.get(i).setWeight(siblings.get(i + 1).getWeight());
                }
                siblings.get(siblings.size() - 1).setWeight(nextWeight);
                source.setWeight(firstWeight);
                updateSelftAndChild(source, target.getParentId(), target.getParentIds(), source.getWeight());
            }

            return;
        }
        //否则作为最后孩子节点
        int nextWeight = nextWeight((ID) target.getId());
        updateSelftAndChild(source, (ID) target.getId(), target.makeSelfAsNewParentIds(), nextWeight);
    }

    /**
     * 把源节点全部变更为目标节点
     *
     * @param source
     * @param newParentIds
     */
    public void updateSelftAndChild(T source, ID newParentId, String newParentIds, int newWeight) {
        String oldSourceChildrenParentIds = source.makeSelfAsNewParentIds();
        source.setParentId(newParentId);
        source.setParentIds(newParentIds);
        source.setWeight(newWeight);
        saveOrUpdate(source);
        String newSourceChildrenParentIds = source.makeSelfAsNewParentIds();
    }

    /**
     * 查找目标节点及之后的兄弟  注意:值与越小 越排在前边
     *
     * @param parentIds
     * @param currentWeight
     * @return
     */
    public List findSelfAndNextSiblings(String parentIds, int currentWeight) {
        List result = new ArrayList();
        List all = getDao().selectAll();
        for (T part : all) {
            if (part.getParentIds().equalsIgnoreCase(parentIds) && part.getWeight() == currentWeight) {
                result.add(part);
            }
        }
        return result;
    }

    /**
     * 查看与name模糊匹配的名称
     *
     * @param name
     * @return
     */
    public Set findNames(Searchable searchable, String name, ID excludeId) throws InvocationTargetException, IllegalAccessException {
        T excludeM = getDao().selectByPrimaryKey(excludeId);

        searchable.addSearchFilter("name", SearchOperator.like, name);
        addExcludeSearchFilter(searchable, excludeM);

        return Sets.newHashSet(
                Lists.transform(
                        findBySearchable(searchable).getRows(),
                        new Function() {
                            public String apply(T input) {
                                return input.getName();
                            }
                        }
                )
        );
    }

    /**
     * 查询子子孙孙
     *
     * @return
     */
    public List findChildren(List parents, Searchable searchable)
            throws InvocationTargetException, IllegalAccessException {
        if (parents.isEmpty()) {
            return Collections.EMPTY_LIST;
        }

        SearchFilter first = CustomConditionFactory.newCustomCondition("parent_ids",
                SearchOperator.prefixLike,
                parents.get(0).makeSelfAsNewParentIds());
        SearchFilter[] others = new SearchFilter[parents.size() - 1];
        for (int i = 1; i < parents.size(); i++) {
            others[i - 1] = CustomConditionFactory.newCustomCondition("parent_ids",
                    SearchOperator.prefixLike,
                    parents.get(i).makeSelfAsNewParentIds());
        }
        searchable.or(first, others);

        List children = getDao().findBySearchable(searchable).getRows();
        return children;
    }

    public List findAllByName(Searchable searchable, T excludeM)
            throws InvocationTargetException, IllegalAccessException {
        addExcludeSearchFilter(searchable, excludeM);
        List list = getDao().findBySearchable(searchable).getRows();
        return list;
    }

    /**
     * 查找根和一级节点
     *
     * @param searchable
     * @return
     */
    public List findRootAndChild(Searchable searchable) throws InvocationTargetException, IllegalAccessException {
        searchable.addSearchParam("parent_id_eq", 0);
        List models = getDao().findBySearchable(searchable).getRows();
        if (ListUtils.isEqualList(models, null))
            return models;
        List ids = Lists.newArrayList();
        for (int i = 0; i < models.size(); i++) {
            ids.add(String.valueOf(models.get(i).getId()));
        }
        searchable.removeSearchFilter("parent_id_eq");
        String[] array = ids.toArray(new String[ids.size()]);
        searchable.addSearchParam("parent_id_in", array);
        models.addAll(getDao().findBySearchable(searchable).getRows());
        return models;
    }

    public Set findAncestorIds(Iterable currentIds) {
        Set parents = Sets.newHashSet();
        for (ID currentId : currentIds) {
            parents.addAll(findAncestorIds(currentId));
        }
        return parents;
    }

    public Set findAncestorIds(ID currentId) {
        Set ids = Sets.newHashSet();
        T m = getDao().selectByPrimaryKey(currentId);
        if (StringUtils.isEmpty(m)) {
            return ids;
        }
        for (String idStr : StringUtils.tokenizeToStringArray(m.getParentIds(), "/")) {
            if (!StringUtils.isEmpty(idStr)) {
                ids.add(Long.valueOf(idStr));
            }
        }
        return ids;
    }

    /**
     * 递归查询祖先
     *
     * @param parentIds
     * @return
     */
    public List findAncestor(String parentIds) throws InvocationTargetException, IllegalAccessException {
        if (StringUtils.isEmpty(parentIds)) {
            return Collections.EMPTY_LIST;
        }
        String[] ids = StringUtils.tokenizeToStringArray(parentIds, "/");
        List results = (List) getDao().findBySearchable(Searchable.newSearchable().addSearchFilter("id", SearchOperator.in, ids));

        return results;
    }

    public void addExcludeSearchFilter(Searchable searchable, T excludeM) {
        if (excludeM == null) {
            return;
        }
        searchable.addSearchFilter("id", SearchOperator.ne, excludeM.getId());
        searchable.addSearchFilter("parent_ids", SearchOperator.suffixNotLike, excludeM.makeSelfAsNewParentIds());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy