我正在尝试使用 Vaadin 编写一个显示“任务”树的应用程序TreeGrid
。
需要注意的一个非常重要的事情是树节点类型不包含对父节点或任何子节点的引用。相反,一个单独的类型包含父/子关系,引用树节点类型的项目的唯一 ID。
这两种类型分别存储在各自的数据库表中。数据本身是从 MS Excel 文件中提取的(不要问为什么)并插入到数据库中,应用程序利用该数据库来访问数据。
为了更直观地呈现这一点:
TaskMaster(树节点类型):
@Entity
public class TaskMaster extends AbstractEntity {
private String internalTaskID;
private String name;
private TaskType type;
// other fields
...
}
TaskRelationship(父/子关系):
@Entity
public class TaskRelationship extends AbstractEntity {
private String taskView;
private String parentTaskID;
private String childTaskID;
// other fields
...
}
我已经编写@Repository
了@Service
课程以方便根据需要检索信息。
我无法弄清楚如何让网格加载和显示代表任务树的节点层次结构。我查看了 Vaadin 示例,并创建了一个数据提供程序来尝试加载此数据,但无济于事。它只加载根节点而不加载其他任何东西。
我想知道当节点对象包含对父母和孩子的引用时,树网格是否只知道如何处理层次关系。我的对象不这样做。相反,我尝试在服务和数据提供者类中设置逻辑以“获取”所需内容。显然这行不通。要么,要么我错过了一些非常微妙的东西。
这是一些代表我努力的代码。
任务主数据提供者:
public class TaskMasterDataProvider
extends AbstractBackEndHierarchicalDataProvider<TaskMaster, Void> {
...
@Override
public int getChildCount(HierarchicalQuery<TaskMaster, Void> query) {
logger.info("parent: {}", query.getParent());
if (query.getParent() != null) {
int count = service.getChildCount(query.getParent());
logger.info("child count: {}", count);
}
return service.getChildCount(query.getParent());
}
@Override
public boolean hasChildren(TaskMaster item) {
logger.info("item: {}", item);
return service.hasChildren(item);
}
@Override
protected Stream<TaskMaster> fetchChildrenFromBackEnd(HierarchicalQuery<TaskMaster, Void> query) {
logger.info("parent: {}", query.getParent());
return service.getChildren(query.getParent()).stream();
}
}
任务主服务:
@Service
@Transactional
public class TaskMasterService {
...
public List<TaskMaster> getTopLevelTasks() {
List<TaskMaster> result = new ArrayList<>();
List<String> topLevelIDs = taskRelationService.getTopLevelParentTaskIDs();
topLevelIDs.forEach(id -> {
TaskMaster task = taskMasterRepo.findByInternalTaskID(id);
if (task != null) {
result.add(task);
}
});
return result;
}
public int getChildCount(TaskMaster parent) {
logger.info("parent: {}", parent);
return parent != null
? taskRelationService.getChildRelationsForParent(parent.getInternalTaskID()).size()
: 0;
}
public boolean hasChildren(TaskMaster parent) {
logger.info("parent: {}", parent);
return parent != null
? !taskRelationService.getChildRelationsForParent(parent.getInternalTaskID()).isEmpty()
: false;
}
public List<TaskMaster> getChildren(TaskMaster parent) {
logger.info("parent: {}", parent);
List<TaskMaster> result = new ArrayList<>();
if (parent != null) {
List<TaskRelationship> childRelations = taskRelationService
.getChildRelationsForParent(parent.getInternalTaskID());
childRelations.forEach(relation -> {
result.add(taskMasterRepo.findByInternalTaskID(relation.getChildTaskID()));
});
}
return result;
}
}
任务树视图:
@Route("tree")
@CssImport("./styles/shared-styles.css")
public class TaskTreeView extends VerticalLayout {
...
private TreeGrid<TaskMaster> taskGrid;
private TaskMasterDataProvider provider;
private TaskMasterService taskService;
public TaskTreeView(TaskMasterService taskService) {
this.taskService = taskService;
setSizeFull();
addClassName("task-tree-grid");
configureView();
}
private void configureView() {
taskGrid = new TreeGrid<>();
taskGrid.addHierarchyColumn(TaskMaster::getName).setHeader("Name");
taskGrid.addColumn(TaskMaster::getType).setHeader("Type");
taskGrid.getColumns().forEach(col -> {
col.setAutoWidth(true);
col.setResizable(true);
});
provider = new TaskMasterDataProvider(taskService);
taskGrid.setDataProvider(provider);
taskGrid.asSingleSelect().addValueChangeListener(event -> {
if (event.getValue() != null) {
provider.refreshItem(event.getValue(), true);
}
});
add(taskGrid);
taskGrid.setItems(taskService.getTopLevelTasks());
}
}
这不是全部,但我认为这是最重要的。如果需要,我可以添加更多。
如果有人知道我的理论是否有任何优点,或者我是否做错了什么,请告诉我。