这是一个场景,我们有一个使用PrimeFaces并在Tomcat 7上运行的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请求,反序列化视图状态对象并在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();
}
答案 0 :(得分:4)
根据JSF规范建议的状态保存方法是通过StateManager
组件。这与JSF运行时在其自身的状态保存操作中使用的组件相同。虽然UIViewRoot#saveState
可能会给出类似的结果,但StateManager
及其便捷方法可提供规范要求的保证。
保存视图状态
获取与您的申请相关联的StateManager
的引用:
FacesContext ctx = FacesContext.getCurrentInstance();
StateManager stateManager = ctx.getApplication().getStateManager();
使用
一个。 Object viewState = stateManager.saveView(ctx);
湾getViewState
便利方法
String viewState stateManager.getViewState(ctx);
恢复视图的状态
UIViewRoot restoredView = stateManager.writeState(ctx,viewState);