我的目标是使会话大小尽可能小。 (为什么?..这是另一个主题)。
我所拥有的是在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_VIEWRENDER_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

07-28 01:22
查看更多