我的目标是使会话大小尽可能小。 (为什么?..这是另一个主题)。
我所拥有的是在faces-config.xml中声明的阶段侦听器
<lifecycle>
<phase-listener>mypackage.listener.PhaseListener</phase-listener>
</lifecycle>
我想将除最后一个(最多两个)之外的所有其他视图保存在某些内存缓存中。获取会话图:
Map<String, Object> sessionMap = event.getFacesContext().getExternalContext().getSessionMap();
在beforePhase(PhaseEvent event)方法中,我可以访问所有视图。因此,在这里我可以将所有视图保存到内存缓存中,并将其从会话中删除。问题是,在jsf中向这些位置请求仍在浏览器中加载的这些视图,以便在需要时可以重新填充该视图。有可能吗?谢谢。
最佳答案
要解决问题的核心,请实施ViewHandler
,在其中可以控制RESTORE_VIEW
和RENDER_RESPONSE
阶段/过程。您将在RENDER_RESPONSE
期间保存视图,并在RESTORE_VIEW
阶段有选择地还原视图。您的视图处理程序可能类似于以下内容
public class CustomViewHandlerImpl extends ViewHandlerWrapper{
@Inject ViewStore viewStore; //hypothetical storage for the views. Could be anything, like a ConcurrentHashMap
ViewHandler wrapped;
public CustomViewHandlerImpl(ViewHandler toWrap){
this.wrapped = toWrap;
}
public UIViewRoot restoreView(FacesContext context, String viewId) throws IOException{
//this assumes you've previously saved the view, using the viewId
UIViewRoot theView = viewStore.get(viewId);
if(theView == null){
theView = getWrapped().restoreView(context, viewId);
}
return theView;
}
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException{
viewStore.put(viewToRender.getId(),viewToRender);
getWrapped().renderView(context, viewToRender);
}
}
只需使用以下命令插入您的自定义视图处理程序
<view-handler>com.you.customs.CustomViewHandlerImpl</view-handler>
当然,您可能不想对所有视图都进行这种处理。您可以随意在上述逻辑中添加任何条件,以实现有条件的视图保存和恢复。
您还应该考虑其他选择。看来您是在这里合并问题。如果您真正关心的是限制与视图处理相关的开销,则应考虑
JSF-2.2新增的无状态视图。无状态视图选项使您可以通过在
transient="true"
上指定f:view
来从JSF视图保存机制中排除特定页面。比手工操作UIViewRoot
干净得多。需要说明的是,无状态视图不能由依赖状态保存的范围(即@ViewScoped
)支持。在无状态视图中,将为每次回发重新创建@ViewScoped
bean。在这种情况下,Ajax功能也会受到影响,因为状态保存是ajax操作的基础。选择性地将标记组件设置为
transient
所有UIComponents
都具有瞬时属性,这意味着,基于每个视图,您可以使用transient="true"
标记特定的组件,有效地为您提供与1)相同的好处,但在范围要小得多。没有ViewScoped的缺点编辑:出于某种原因,
UIViewRoot#getViewId()
不会返回当前视图的名称(这可能是一个错误)。或者,您可以使用ExternalContext extCtxt = FacesContext.getCurrentInstance().getExternalContext();
String viewName = ((HttpServletRequest)extCtxt.getRequest()).getRequestURI(); //use this id as the key to store your views instead