JSF保存/恢复视图状态



这是一个场景,我们有一个使用PrimeFaces并在Tomcat7上运行的JSF应用程序,所有托管bean都是ViewScoped的,它们的结构非常复杂。最近,我们被要求实现以下要求:生成一个可以在用户之间共享的URL。通过单击链接,视图应恢复到以前生成链接时保存的状态。

一般来说,我的想法是实现一个阶段侦听器,并相应地对viewRoot对象调用saveState/restoreState。在生成URL时,phaseListener将通过调用saveState获得UIViewRoot状态,然后序列化对象并将其持久化到数据库表中。访问链接时会发生相反的情况,对象将从数据库中检索,通过调用restoredState在UIViewRoot上进行反序列化和还原。

当尝试恢复状态时,实际结果并不是我所期望的,因为在UIViewRoot上调用restoreState后,托管bean属性为null。

saveState是在渲染阶段完成后调用的,如果所有值都设置正确,则可序列化对象看起来不错。restoreState是在"恢复视图"阶段调用的,在调用restoreState的时间(在阶段之后/之前(,我已经尝试了很多组合,但似乎都不起作用。

出于测试目的,我在PhaseListener中实现了这些方法。以下是代码片段,省略了调用它们的逻辑:

private void saveState(FacesContext context) {
    UIViewRoot viewRoot = context.getViewRoot();    
    Object savedState = viewRoot.saveState(context);
    if(savedState instanceof Serializable) {
        Serializable s = ((Serializable) savedState);
        try {
            this.serialize(s);
        } catch (IOException e) {
            logger.error("Error saving state.", e);
        }
     }
}
private void restoreState(FacesContext context) {
    UIViewRoot viewRoot = new UIViewRoot();
    FileInputStream fis;
    try {
        fis = new FileInputStream("/view.ser");
        Serializable savedState = this.deserialize(fis);
        viewRoot.restoreState(context, savedState);
    } catch (ClassNotFoundException | IOException e) {
        logger.error("Error restoring state.", e);
    }
}

我不是JSF专家,因此我不确定我尝试使用的方法是否有任何意义,所以我向JSF大师们提出了一个问题:这个需求能以某种方式实现吗?如果是,正确的实施方式是什么?我研究过这个论坛,找不到类似的东西可以重复使用。

任何帮助都将不胜感激。谢谢。

更新

这就是我们保存和恢复视图状态的方法。

视图状态正在web bean中保存和序列化:

private void saveViewState(FacesContext context) throws IOException {
    UIViewRoot viewRoot = context.getViewRoot();
    Object savedState = viewRoot.saveState(context);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(savedState);
}

为了恢复状态,阶段侦听器在恢复视图阶段之前截获Faces Request,反序列化视图状态对象,并在UIViewRoot:上调用restoreState

private void restoreState(FacesContext context) {
    // details omitted
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    ObjectInputStream ois = new ObjectInputStream(bais);
    Serializable viewState = (Serializable) ois.readObject();
    UIViewRoot viewRoot = new UIViewRoot();
    viewRoot.restoreState(context, viewState);
    viewRoot.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
    viewRoot.setViewId(savedView.getViewId());
    context.setViewRoot(viewRoot);
    context.renderResponse();
}

根据JSF规范,推荐的状态保存方法是通过StateManager组件。这是JSF运行时在其自己的状态保存操作中使用的相同组件。虽然UIViewRoot#saveState可能会给出类似的结果,但StateManager及其方便的方法提供了规范要求的保证

  • 保存视图状态

    1. 获得与您的应用程序相关的StateManager的参考:

      FacesContext ctx = FacesContext.getCurrentInstance();
      StateManager stateManager = ctx.getApplication().getStateManager();
      
    2. 使用任一

      a。Object viewState = stateManager.saveView(ctx);

      b。getViewState方便方法

      String viewState stateManager.getViewState(ctx);
      
  • 恢复视图的状态

    UIViewRoot restoredView = stateManager.writeState(ctx,viewState);
    

相关内容

  • 没有找到相关文章

最新更新