3.5.13.3. 使用 URL 历史和导航 API

本章节包含使用 URL 历史和导航 API 的示例。

假设有 Task - 任务 实体和 TaskInfo 界面,用来展示选中任务的信息。

TaskInfo 界面控制器包含 @Route 注解,用来指定此界面的路由:

  1. package com.company.demo.web.navigation;
  2. import com.haulmont.cuba.gui.Route;
  3. import com.haulmont.cuba.gui.screen.Screen;
  4. import com.haulmont.cuba.gui.screen.UiController;
  5. import com.haulmont.cuba.gui.screen.UiDescriptor;
  6. @Route("task-info")
  7. @UiController("demo_TaskInfoScreen")
  8. @UiDescriptor("task-info.xml")
  9. public class TaskInfoScreen extends Screen {
  10. }

然后,用户可以在浏览器的地址栏输入 http://localhost:8080/app/#main/task-info 来打开此界面:

url screen by route

当界面打开时,地址还包含一个状态标记。

状态与 URL 的映射

假设 TaskInfo 界面每次展示一个任务的信息,并且能控制切换选取的任务。也许需要在 URL 中反应当前查看的任务,这样可以拷贝 URL,以便之后可以在浏览器的地址栏粘贴 URL 就能打开查看此特定任务的界面。

下面的代码实现了选中任务和 URL 的映射:

  1. package com.company.demo.web.navigation;
  2. import com.company.demo.entity.Task;
  3. import com.google.common.collect.ImmutableMap;
  4. import com.haulmont.cuba.gui.Route;
  5. import com.haulmont.cuba.gui.UrlRouting;
  6. import com.haulmont.cuba.gui.components.Button;
  7. import com.haulmont.cuba.gui.components.LookupField;
  8. import com.haulmont.cuba.gui.screen.*;
  9. import com.haulmont.cuba.web.sys.navigation.UrlIdSerializer;
  10. import javax.inject.Inject;
  11. @Route("task-info")
  12. @UiController("demo_TaskInfoScreen")
  13. @UiDescriptor("task-info.xml")
  14. @LoadDataBeforeShow
  15. public class TaskInfoScreen extends Screen {
  16. @Inject
  17. private LookupField<Task> taskField;
  18. @Inject
  19. private UrlRouting urlRouting;
  20. @Subscribe("selectBtn")
  21. protected void onSelectBtnClick(Button.ClickEvent event) {
  22. Task task = taskField.getValue(); (1)
  23. if (task == null) {
  24. urlRouting.replaceState(this); (2)
  25. return;
  26. }
  27. String serializedTaskId = UrlIdSerializer.serializeId(task.getId()); (3)
  28. urlRouting.replaceState(this, ImmutableMap.of("task_id", serializedTaskId)); (4)
  29. }
  30. }
1- 从 LookupField 获取当前任务
2- 如果没有选中任务,移除 URL 参数
3- 使用 UrlIdSerializer 来序列化任务的 id
4- 用包含序列化任务 id 参数的新状态替换当前的 URL 状态。

结果是,当用户选中任务然后点击 Select Task 按钮时,应用程序 URL 会变化:

url reflection state

UrlParamsChangedEvent

现在实现最后一个需求:当用户输入带路由和 task_id 参数的 URL 时,应用程序必须展示相应任务的界面。下面是完整的界面控制器代码。

  1. package com.company.demo.web.navigation;
  2. import com.company.demo.entity.Task;
  3. import com.google.common.collect.ImmutableMap;
  4. import com.haulmont.cuba.core.global.DataManager;
  5. import com.haulmont.cuba.gui.Route;
  6. import com.haulmont.cuba.gui.UrlRouting;
  7. import com.haulmont.cuba.gui.components.Button;
  8. import com.haulmont.cuba.gui.components.LookupField;
  9. import com.haulmont.cuba.gui.navigation.UrlParamsChangedEvent;
  10. import com.haulmont.cuba.gui.screen.*;
  11. import com.haulmont.cuba.web.sys.navigation.UrlIdSerializer;
  12. import javax.inject.Inject;
  13. import java.util.UUID;
  14. @Route("task-info")
  15. @UiController("demo_TaskInfoScreen")
  16. @UiDescriptor("task-info.xml")
  17. @LoadDataBeforeShow
  18. public class TaskInfoScreen extends Screen {
  19. @Inject
  20. private LookupField<Task> taskField;
  21. @Inject
  22. private UrlRouting urlRouting;
  23. @Inject
  24. private DataManager dataManager;
  25. @Subscribe
  26. protected void onUrlParamsChanged(UrlParamsChangedEvent event) {
  27. String serializedTaskId = event.getParams().get("task_id"); (1)
  28. UUID taskId = (UUID) UrlIdSerializer.deserializeId(UUID.class, serializedTaskId); (2)
  29. taskField.setValue(dataManager.load(Task.class).id(taskId).one()); (3)
  30. }
  31. @Subscribe("selectBtn")
  32. protected void onSelectBtnClick(Button.ClickEvent event) {
  33. Task task = taskField.getValue();
  34. if (task == null) {
  35. urlRouting.replaceState(this);
  36. return;
  37. }
  38. String serializedTaskId = UrlIdSerializer.serializeId(task.getId());
  39. urlRouting.replaceState(this, ImmutableMap.of("task_id", serializedTaskId));
  40. }
  41. }
1- 从 UrlParamsChangedEvent 获取参数值
2- 对任务 id 进行反序列化
3- 加载任务实例并设置到界面控件