在JSF应用中,特别是ajax应用,一般都涉及到页面内及页面跳转时状态维持的问题,举两个例子来说明这个问题:
1. 在一个页面中,点击某个按钮发送ajax请求,执行服务器端一个方法,如果这个方法里改变了Mbean中某个属性的值,下次再点击这个按钮时,需要访问这个已经修改过的属性值,如果Mbean是requestScope的,这个属性的值如何在两次请求间维持?
2. 在一个页面中,点击某个按钮跳转至另一页面,如果另一页面的正确渲染信赖于前一个页面的Mbean在redirect之前保存的状态值,前一个页面的Mbean是requestScope的,redirect之后将被销毁,这时redirect之后如何能取得保存的状态?
针对这个问题weld(这是jsr299即之前的webbeans规范的参考实现),jsf2.0都提供了解决方案
weld的方案:
它提供一个transactionScope,这个可以看作为短时间范围的sessionScope
每个请求都被赋予一个transactionContext,并以cid作为标识符
同一个对话的请求将都带有一个cid参数,请求到达服务器端时将根据cid参数将对应的transactionContext与之绑定,则在请求的处理过程中将可以访问保存在transactionContext中的状态变量,从而达到了在多个请求间维持状态的目标。
对话有一个超时时间(这个超时时间远小于session的超时时间,所以说这是一个短时间范围的sessionScope),如果在这个时间内没有新的请求将其激活,则对话上下文被销毁。
如果发生页面跳转,则需要在跳转的url上添加cid参数,则在跳转后依然可以访问transactionContext中的状态变量
jsf2.0的方案:
它提供一个viewScope,在一个UIViewRoot中所有组件触发的ajax请求到达服务器端后,可以访问viewScope中的状态变量,这些状态变量在多次请求间得到维持。由于它的实现原理是将这些状态变量保存在viewState中,依靠jsf自身的viewState的保存与还原机制的,所以可知对这些状态变量有限制:要么是基本类型,要么实现序列化接口,要么实现javax.faces.component.StateHolder接口,这不能不说是一个遗憾。
为了跳转页面传递参数,jsf2.0提供一种flash(这里所说的flash不是adobe的flash)的机制。了解过ruby on rails的都知道rails有这样一个特性:
在重定向之前可以向一个名为flash的特定对象扔进参数,在重定向的页面中即可从flash的特定对象中取到参数,flash对象中保存的内容将在下一次重定向时清除。
jsf2.0为页面重定向时页面间参数的传递也是提供这种解决方案。