Слишком много предметов в дереве Ваадинов


Я создаю веб-приложение с помощью Vaadin, одна из функций требует дерево для отображения элементов, проблема в том, что это дерево загружается до (40K) элементов или даже больше.

На уровне нескольких тысяч элементов Дерево Ваадина приемлемо, но сейчас это не так, и оно замедляет все в веб-браузере.

То, что я имею в виду, это разбиение нагрузки на страницы между веб-сервером и веб-клиентом и отображение нескольких элементов, которые обновляются при прокрутке пользователем дерева, проблема в том, что я не знаю, с чего начать, и даже если это применимо или нет.

Это хороший подход? Есть ли лучший вариант? отказ от дерева для таблицы не является решением, клиент не хочет этого делать.

4 3

4 ответа:

Вы можете лениво загружать содержимое дерева, добавляя динамически дочерние узлы при расширении узлов дерева. Основная идея подхода, который я использовал много раз, заключается в следующем:

final Tree tree = new Tree();
//get the top level collection of entities
        Collection<MyEntity> myEntitiesCategories = findEntities(MyEntity.class);//findEntities is one of your method that retrieves entities from a datasource
        for (MyEntity myEntity : myEntitiesCategories) {
            tree.addItem(myEntity);
        }
        tree.addListener(new Tree.ExpandListener() {

            @Override
            public void nodeExpand(ExpandEvent event) {
                MyEntity myEntityCategory = (MyEntity) event.getItemId();
                Collection<MyEntity> myEntities = myEntityCategory.getChildrenMyEntities();
                for (MyEntity myEntity : myEntities) {
                    tree.addItem(myEntity);
                    tree.setParent(myEntity, myEntityCategory);
                    tree.setChildrenAllowed(myEntity, false);//the boolean value could also be true, it depends on whether it can have children or not
                }
            }
        });

Я бы рекомендовал вам использовать TreeTable вместо Tree в этом случае. Он лениво загружает строки с сервера на клиент, чтобы не замедлять работу браузера.

Насколько я знаю, компонент Tree не поддерживает встроенную ленивую загрузку (что было бы наиболее удобно для всех нас).

Одним из подходов было бы:

  • реализуйте свои собственные Collapsible контейнер как источник данных
  • лениво загружайте элементы дерева из контейнера после расширения узла дерева с использованием Tree.ExpandListener

Здесь вы можете найти пример использования дерева.Расширитель.
здесь вы можете найти пример реализация сборно-разборного контейнера.

Я надеюсь, что это помогает.

Хотя в документации Vaadin говорится, что ленивая загрузка для Tree не поддерживается, мне удалось реализовать следующую ленивую загрузку Hierarchical интерфейс.

Это очень важно хранить все элементы в локальной структуре (в моем случае в HashMap hierarchy), не считывайте элементы несколько раз это не работает. Я думаю, потому что Ваадин не использует equals() и hashCode().

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.softmodeler.common.CommonPlugin;
import com.softmodeler.model.OutputNode;
import com.softmodeler.service.IViewService;
import com.vaadin.data.Container.Hierarchical;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItem;

/**
 * @author Flavio Donzé
 * @version 1.0
 */
public class OutputNodeHierachical implements Hierarchical {
    private static final long serialVersionUID = 8289589835030184018L;

    /** the view service */
    private IViewService service = CommonPlugin.getService(IViewService.class);

    /** collection of all root nodes */
    private List<OutputNode> rootNodes = null;
    /** parent=>children mapping */
    private Map<OutputNode, List<OutputNode>> hierarchy = new HashMap<>();

    /**
     * constructor
     *
     * @param rootNodes collection of all root nodes
     */
    public OutputNodeHierachical(List<OutputNode> rootNodes) {
        this.rootNodes = Collections.unmodifiableList(rootNodes);

        addToHierarchy(rootNodes);
    }

    @Override
    public Collection<?> getChildren(Object itemId) {
        try {
            List<OutputNode> children = hierarchy.get(itemId);
            if (children == null) {
                OutputNode node = (OutputNode) itemId;
                children = service.getChildren(node.getNodeId(), false);

                hierarchy.put(node, children);

                // add children to hierarchy, their children will be added on click
                addToHierarchy(children);
            }
            return children;
        } catch (Exception e) {
            VaadinUtil.handleException(e);
        }
        return null;
    }

    /**
     * add each element to the hierarchy without their children hierarchy(child=>null)
     *
     * @param children elements to add
     */
    private void addToHierarchy(List<OutputNode> children) {
        for (OutputNode child : children) {
            hierarchy.put(child, null);
        }
    }

    @Override
    public boolean areChildrenAllowed(Object itemId) {
        return !((OutputNode) itemId).getChilds().isEmpty();
    }

    @Override
    public boolean hasChildren(Object itemId) {
        return !((OutputNode) itemId).getChilds().isEmpty();
    }

    @Override
    public Object getParent(Object itemId) {
        String parentId = ((OutputNode) itemId).getParentId();
        for (OutputNode node : hierarchy.keySet()) {
            if (node.getNodeId().equals(parentId)) {
                return node;
            }
        }
        return null;
    }

    @Override
    public Collection<?> rootItemIds() {
        return rootNodes;
    }

    @Override
    public boolean isRoot(Object itemId) {
        return rootNodes.contains(itemId);
    }

    @Override
    public Item getItem(Object itemId) {
        return new BeanItem<OutputNode>((OutputNode) itemId);
    }

    @Override
    public boolean containsId(Object itemId) {
        return hierarchy.containsKey(itemId);
    }

    @Override
    public Collection<?> getItemIds() {
        return hierarchy.keySet();
    }

    @Override
    public int size() {
        return hierarchy.size();
    }

    @Override
    public boolean setParent(Object itemId, Object newParentId) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Item addItem(Object itemId) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Object addItem() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeItem(Object itemId) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeAllItems() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Class<?> getType(Object propertyId) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Collection<?> getContainerPropertyIds() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Property<?> getContainerProperty(Object itemId, Object propertyId) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

}

Добавление контейнера в Tree как это:

OutputNodeHierachical dataSource = new OutputNodeHierachical(rootNodes);

Tree mainTree = new Tree();
mainTree.setSizeFull();
mainTree.setContainerDataSource(dataSource);
mainTree.addItemClickListener(new ItemClickListener() {
    private static final long serialVersionUID = -413371711541672605L;

    @Override
    public void itemClick(ItemClickEvent event) {
        OutputNode node = (OutputNode) event.getItemId();
        openObject(node.getObjectId());
    }
});


я надеюсь, что этот пример поможет другим, так как я не нашел реального примера в интернете.