0

当我将组件添加到 Vaadin 的组件(例如TabSheetor Tree)时,添加的组件会被缓存。当用户单击选项卡(或树节点)时,如果它包含 db data ,则显示 stale data ,不反映最新的 db 状态。

我想知道是否有任何方法可以确保加载最新数据?

我通过定义我的自定义界面来解决这个问题:

public interface Reloadable {
  void reload();
}

并且每个组件都实现了这个 Reloadable 接口,例如:

@SpringComponent
public class TeachersView extends VerticalLayout implements Reloadable, Serializable {

  @Inject
  private TeacherDao teacherDao;
  private final static int PAGESIZE = 10;

  private MTable<Teacher> mTable = new MTable<>(Teacher.class);

  @PostConstruct
  public void init() {
    // mTable settings skip here
    reload();
    addComponent(mTable);
  }

  @Override
  public void reload() {
    mTable.setBeans(new SortableLazyList<>(
      sortablePagingProvider ,
      () -> (int) teacherDao.count() ,
      PAGESIZE
    ));
  }

  private SortableLazyList.SortablePagingProvider<Teacher> sortablePagingProvider =
    (firstRow, asc, sortProperty) -> {  
      return teacherDao.findAll(
        new PageRequest(
          firstRow / PAGESIZE, PAGESIZE,
          asc ? Sort.Direction.ASC : Sort.Direction.DESC,
          sortProperty == null ? "id" : sortProperty
        )
      ).getContent();
    };
}

这个视图被注入到UI类中:

@SpringUI(path = "/ui")
@Theme("valo")
public class VaadinUI extends UI {
  @Inject
  private TeacherDao teacherDao;

  @Inject
  private TeachersView teachersView;

  @Override
  protected void init(VaadinRequest vaadinRequest) {
    Panel panel = new Panel("Admin Panel");

    HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
    splitPanel.setSplitPosition(15, Unit.PERCENTAGE);
    panel.setContent(splitPanel);

    Tree tree = new Tree("Menu");
    splitPanel.setFirstComponent(tree);

    Label home = new Label("Home");

    Map<String, Component> map = new HashMap<>();
    map.put("Teachers", teachersView);
    map.put("Home", home);

    map.forEach((k, v) -> tree.addItem(k));

    tree.addItemClickListener(event -> {

      Component view = map.get(event.getItemId());
      if (view instanceof Reloadable) {
        ((Reloadable) view).reload();
      }
      splitPanel.setSecondComponent(view);
    });

    splitPanel.setSecondComponent(home);
    setContent(panel);
  } // init()
}

注意tree.addItemClickListener,我必须检查每个组件是否实现Reloadable,如果为 true,则调用它。

有用 。但我不知道这是否是实现这一目标的标准方式?我认为这应该是一个常见的场景,应该有类似组件的内置接口来实现,比如onRender那个(但我找不到)。我错过了什么吗?

谢谢。

4

1 回答 1

1

首先,我将推荐您可能已经看过的有关Spring 和 Vaadin的教程,但我会在一些地方引用它,我认为这是 Vaadin 和 Spring 集成的一个很好的起点。

其次,出于好奇,您为什么要使用树来构建菜单?

在提供的示例中,您似乎正在对某些视图功能之间的导航进行建模,该功能已在 Vaadin 中可用,并且由于您使用的是Spring,Vaadin springspring-boot扩展使得在视图之间定义和导航变得非常容易. 然后,您可以为每个视图在它们自己的enter()方法中定义一些特定的行为。我使用Vaadin 仪表板演示作为以下更改的灵感:

@SpringView(name = TeachersView.NAME)
public class TeachersView extends VerticalLayout implements View {
    public static final String NAME = "Teachers";

    private Label title = new Label("Teachers view");

    @PostConstruct
    void init() {
        addComponent(title);
    }

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        // recreate or reload stuff here
        title.setValue("Teachers view reloaded @ " + new Date());
    }
}
@SpringView(name = HomeView.NAME)
public class HomeView extends VerticalLayout implements View {
    public static final String NAME = "";

    @PostConstruct
    void init() {
        addComponent(new Label("Home"));
    }

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        // meh, nothing special to do here
    }
}
public class SpringVaadinUI extends UI {

    @Autowired
    private SpringViewProvider viewProvider;

    @Override
    protected void init(VaadinRequest vaadinRequest) {
        addStyleName(ValoTheme.UI_WITH_MENU);
        Panel panel = new Panel("Admin Panel");

        HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
        splitPanel.setSplitPosition(15, Unit.PERCENTAGE);
        panel.setContent(splitPanel);

        VerticalLayout navigationBar = new VerticalLayout();
        navigationBar.setPrimaryStyleName(ValoTheme.MENU_ROOT);
        navigationBar.addComponent(createNavigationButton("Home", FontAwesome.HOME, HomeView.NAME));
        navigationBar.addComponent(createNavigationButton("Teachers", FontAwesome.GROUP, TeachersView.NAME));
        splitPanel.setFirstComponent(navigationBar);

        CssLayout navigationDisplay = new CssLayout();
        splitPanel.setSecondComponent(navigationDisplay);

        Navigator navigator = new Navigator(this, navigationDisplay);
        navigator.addProvider(viewProvider);

        setContent(panel);
    }

    private Button createNavigationButton(String caption, FontAwesome icon, final String viewName) {
        Button button = new Button(caption, icon);
        button.setPrimaryStyleName(ValoTheme.MENU_ITEM);
        button.addStyleName(ValoTheme.BUTTON_SMALL);
        button.addStyleName(ValoTheme.BUTTON_BORDERLESS);
        button.addClickListener(event -> getUI().getNavigator().navigateTo(viewName));
        return button;
    }
}

结果类似于: 演示

如果由于某种原因您不能或不想使用导航器,那么您的解决方案看起来不错。尽管如此,无论您选择使用哪种解决方案,您都应该知道默认情况下Spring 会创建单例。除了 UI 等少数之外,您可能应该将组件更改为原型,以便每次都能获得一个新实例。否则,您的所有用户在访问应用程序时都会获得相同的实例,我认为您不希望发生这种情况。

于 2016-03-10T11:40:14.263 回答