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

一般而言,我的想法是实现一个阶段侦听器,并相应地对viewRoot对象调用saveState / restoreState。在生成URL时,phaseListener将通过调用saveState来获取UIViewRoot状态,然后序列化该对象并保存在数据库表中。当访问链接时,将发生相反的情况,该对象将从数据库中检索,反序列化并通过调用restoreState在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,反序列化视图状态对象并在restoreState上调用UIViewRoot

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及其便利方法提供了规范要求的保证。


保存视图状态


获取对与您的应用程序关联的StateManager的引用:

FacesContext ctx = FacesContext.getCurrentInstance();
StateManager stateManager = ctx.getApplication().getStateManager();

使用任一

一个。 Object viewState = stateManager.saveView(ctx);

b。 getViewState便捷方法

String viewState stateManager.getViewState(ctx);


恢复视图状态

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

09-11 19:33
查看更多