Tapestry4.1.5 tree组件问题的解决及页面缓存带来的问题
defencez
2008-09-27
Tapestry使用缓存来极大地提高效率,根据使用情况,使用缓存能提高大约50%
(甚至更高,当然,编程时应具有比较良好的风格,且对Tapestry的缓存机制比较了解),首先,当一个页第一次被访问,该页以对象方式生成后,其中所有属性首次初始化,页面访问完毕后,被放入页面cache pool中,当再次访问该页时,不会再生成该页面对象,而是直接从缓存中拿出使用,极大提高效率。第二,页面中属性不会再次生成,节省了对象创建的开销。但同时也带来多用户操作时,属性值不更新的问题。 缓存带来的两方面问题 例如,在树组件的使用中,其中有treeModel属性,该属性为构建整个树的入口点,是一个开销比较大的对象,特别是树节点值从数据库提取的情况下,代码如下 public ITreeModel getTreeModel() { if(treeModel == null){ initTree();//构造树的数据都来自于数据库 } return treeModel; } 当关闭Tapestry page cache时,只要页面被再次访问(刷新),则treeModel被清空,则每次都必将执行initTree()的动作,这会反复读取数据库,造成效率的极大降低。其次,B/S架构下的无状态连接协议,首次点击树中的节点(树不是由JavaScript构建,状态更新由服务端完成),向服务端有提交该点击请求,则更新当前页面,展开或收缩节点动作无法完成,因为二次提交后,执行上面的代码,此时treeModel为空,树将被重新构建,先前树状态丢失。 当开启Tapestry page cache时,若treeModel不为空,则initTree()不会被执行,且二次提交后(指点击树节点提交点击请求),页面treeModel属性保持了上一次的状态,根据此次请求展开或收缩节点动作得以执行,可明显见到页面访问快了很多(大概快了75%)。换另一台机器访问该页面,却发现两台机器看到的树的状态是一模一样的,另一台机器本该看到一棵刚初始化完毕的树。 解决 因为Tapestry应用应该开启页面缓存机制,以提高应用的性能,因此,只说在页面缓存开启的情况下的解决方案,其实以下的两种方案都可以用在未开启页面缓存的情况。 自建一Session对象 在Tapestry中,可自建一个能持久化的对象(implements Serializable,即可),把需要临时存储的放入该对象。如下面的代码 if (treeModel == null) { if(this.getApplicationSession().getTreeModel() != null){ treeModel = this.getApplicationSession().getTreeModel(); treeDataModel = this.getApplicationSession().getTreeDataModel(); }else{ initTree(); this.getApplicationSession().setTreeModel(treeModel); this.getApplicationSession().setTreeDataModel(treeDataModel); } }else{ this.getApplicationSession().setTreeModel(treeModel); this.getApplicationSession().setTreeDataModel(treeDataModel); } 在Hivemind中的配置片断 <contribution configuration-id="tapestry.state.ApplicationObjects"> <state-object name="applicationSession" scope="session"> <create-instance class="com.soa.system.ApplicationSession"/> </state-object> </contribution> 代码中,ApplicationSession就是一执行了序列化接口的普通对象。 利用Session对象 每个页面访问,都会有一个HTTP的Session对象,那么在这个Session对象中存储treeModel,判断当前的treeModel的情况,每次都更新Session对象中存储的treeModel,这样就可以既利用了缓存,又能使不同用户视图所看到的树状态不同,且不会造成相同,就可判断访问是不是来自于同一个Session,这就可以解决不同用户看到同一种树状态的问题。 以上两种做法其实是等同的,虽然解决了问题,但有缺陷,当用户离开了这个页面,转入其他页面之后再回到此页面,此页面的树状态仍然是用户离开时的样子,就是说,清空对象中的treeModel属性的时机不好控制。 以下是代码片断 首先注入HttpRequest对象 @InjectObject("service:tapestry.globals.HttpServletRequest") public abstract HttpServletRequest getRequest(); 然后: if(getRequest().getSession().getAttribute("treeModel") == null){ initTree(); getRequest().getSession().setAttribute("treeModel",treeModel); getRequest().getSession().setAttribute("treeDataModel",treeDataModel); }else{ treeModel = (ITreeModel)getRequest().getSession().getAttribute("treeModel"); treeDataModel = (SimpleTreeDataModel)getRequest().getSession().getAttribute("treeDataModel"); } return treeModel; 注意:在存储treemodel时,treeDataModel也需一并存储 所有代码是本人在做一Tapestry工程中的一段代码,因代码太长,此处只贴出有关的代码,不知这里格式怎么整理,显得很乱,大家将就看看吧。 这两种方式在t4.1.5及t4.1.6下面都运行正常。 |
|
defencez
2008-09-27
对上面的补充:
那属性是否是重新初始化,要看用户在何处定义的,如在页面规范文件中定义,则T每次都自动初始化,若在页面类文件中定义的,需要手工初始化。 重载initialize()方法,在该方法中做属性初始化,则T每次会自动调用该方法。 |
|
zbyidingxing
2008-10-27
我刚接触tapestry 我现在项目用的是4.0 也是做了一颗树 请问如何在树结点上挂上url连接 可以实现跳转
谢谢了 |
|
defencez
2008-10-28
T是实现了PME模型的,点击树节点后,可以得到节点的值,也就是节点选择的事件,在页面类中做一getSelectedNode的方法(方法你自行定义)在该方法中实现跳转即可
|