Слишком много предметов в дереве Ваадинов
Я создаю веб-приложение с помощью Vaadin, одна из функций требует дерево для отображения элементов, проблема в том, что это дерево загружается до (40K) элементов или даже больше.
На уровне нескольких тысяч элементов Дерево Ваадина приемлемо, но сейчас это не так, и оно замедляет все в веб-браузере.
То, что я имею в виду, это разбиение нагрузки на страницы между веб-сервером и веб-клиентом и отображение нескольких элементов, которые обновляются при прокрутке пользователем дерева, проблема в том, что я не знаю, с чего начать, и даже если это применимо или нет.
Это хороший подход? Есть ли лучший вариант? отказ от дерева для таблицы не является решением, клиент не хочет этого делать.
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()); } });
я надеюсь, что этот пример поможет другим, так как я не нашел реального примера в интернете.