如何在需要时保存和回收视图 [英] How to save and retrive view when it's needed

查看:112
本文介绍了如何在需要时保存和回收视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是保持会议规模尽可能小。 (为什么?这是其他话题)。
我拥有的是在faces-config.xml中声明的阶段监听器

$ p $ < lifecycle>
<相位侦听器> mypackage.listener.PhaseListener< /相位侦听器>
< / lifecycle>

我想在一些memcache中保存除最后一个(最多两个)以外的所有其他视图。获得会议地图:

 地图< String,Object> sessionMap = event.getFacesContext()。getExternalContext()。getSessionMap();在beforePhase(PhaseEvent事件)方法中,

使我可以访问所有视图。因此,在这里我可以将所有视图保存到memcache并从会话中删除它们。问题是,在jsf中,仍然在浏览器中加载这些视图的请求,以便在需要时可以重新填充此视图。它有可能吗?谢谢。

解决方案

为了解决您的问题的核心问题,请执行 ViewHandler ,您可以在其中控制 RESTORE_VIEW RENDER_RESPONSE 阶段/过程。您将在 RENDER_RESPONSE 期间保存视图,并在 RESTORE_VIEW 阶段有选择地恢复。您的视图处理程序可能如下所示:

  public class CustomViewHandlerImpl extends ViewHandlerWrapper {

@Inject ViewStore viewStore; //视图的假设存储。可以是任何东西,比如一个ConcurrentHashMap
ViewHandler包装;

public CustomViewHandlerImpl(ViewHandler toWrap){
this.wrapped = toWrap;
}

public UIViewRoot restoreView(FacesContext context,String viewId)throws IOException {

//假设您以前保存过视图,使用viewId

UIViewRoot theView = viewStore.get(viewId);

if(theView == null){

theView = getWrapped()。restoreView(context,viewId);
}

返回视图;


$ b $ 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> 






当然,您可能不希望对所有的观点给予这种待遇;你可以自由地添加任何条件到上面的逻辑,实现有条件的视图保存和恢复。






您应该也考虑其他选择。看来你在这里混淆了一些问题。如果您真正关心的是限制与视图处理相关的开销,您应该考虑


  1. 无状态视图 ,JSF-2.2新增功能。通过在 f:view上指定 transient =true,无状态视图选项允许您从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(); //使用这个ID作为存储你的视图的键


My goal is to keep session size as small as possible. (Why?.. it's other topic). What I have is Phase listener declared in faces-config.xml

<lifecycle>
        <phase-listener>mypackage.listener.PhaseListener</phase-listener>   
</lifecycle>

I want to save all other views, except the last one(maximum two) , in some memcache. Getting the session map:

Map<String, Object> sessionMap = event.getFacesContext().getExternalContext().getSessionMap();

in beforePhase(PhaseEvent event) method is giving me access to all views. So here I could save all views to the memcache and delete them from the session. The question is where in jsf these views that are still loaded in the browser are requested so that I can refill with this view if it's needed. Is it possible at all? Thank you.

解决方案

To address the core of your question, implement a ViewHandler, within which you can take control of the RESTORE_VIEW and RENDER_RESPONSE phases/processes. You'll save the view during the RENDER_RESPONSE and selectively restore, during the RESTORE_VIEW phase. Your view handler could look something like the following

   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);

      }

   }

Simply plug in your custom viewhandler, using

<view-handler>com.you.customs.CustomViewHandlerImpl</view-handler>


Of course, you probably don't want to give this treatment to all your views; you're free to add any conditions to the logic above, to implement conditional view-saving and restoration.


You should also consider other options. It appears that you're conflating issues here. If your true concern is limit the overhead associated with view processing, you should consider

  1. Stateless Views, new with JSF-2.2. The stateless view option allows you to exclude specific pages from the JSF view-saving mechanism, simply by specifying transient="true" on the f:view. Much cleaner than mangling the UIViewRoot by hand. The caveat here is that a stateless view cannot be backed by scopes that depend on state-saving, i.e. @ViewScoped. In a stateless view, the @ViewScoped bean is going to be recreated for every postback. Ajax functionality also suffers in this scenario, because state saving is the backbone of ajax-operations.

  2. Selectively set mark components as transient The transient property is available for all UIComponents, which means, on a per-view basis, you can mark specific components with transient="true", effectively giving you the same benefits as 1) but on a much smaller scope. Without the downside of no ViewScoped

EDIT: For some reason, UIViewRoot#getViewId() is not returning the name of the current view (this might be a bug). Alternatively, you can use

ExternalContext extCtxt = FacesContext.getCurrentInstance().getExternalContext();
String viewName = ((HttpServletRequest)extCtxt.getRequest()).getRequestURI();  //use this id as the key to store your views instead

这篇关于如何在需要时保存和回收视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆