深入理解Tapestry的Rewind
程序员文章站
2022-03-14 09:04:36
...
Tapestry的rewind一直是学习和使用Tapestry的难点,rewind是用来处理表单提交的,表单默认使用的是DirectService来提交。在详细介绍之前,先说明下此文中需要用到的一些概念,首先是表单组件,我这里指的是指继承自AbstractFormComponent类的组件,例如:TextField、TextArea、Checkbox等,而不是具体的Form组件,表单组件使用时必须在Form组件中,这些组件在rewind时调用继承自AbstractFormComponent的rewindFormComponent来读取数据,并将数据赋值给容器或者页面。
我们来看一下最简单的TextField组件,组件定义如下
再看一下TextField中的rewindFormComponent组件方法
可以看到在rewindFormComponent中,主要是从请求中取得用户输入的值,然后进行处理,最后赋值给容器或者页面,上面的例子中会调用页面类的getPicture().setPrice(“用户输入的值”)来进行赋值。这样整个表单的提交就可以理解为所有的表单组件读取用户输入的值并赋值给页面的过程。
整个表单提交的详细处理过程如下:
我们来看一下最简单的TextField组件,组件定义如下
<input jwcid="price@TextField" type="text" value="ognl:picture.price" translator="translator:number,pattern=##.##" validators="validators:min=0" displayName="价格" class="input_text"/>
再看一下TextField中的rewindFormComponent组件方法
protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle) { //从请求中得到参数值 String value = cycle.getParameter(getName()); try { //用translator来转换值 Object object = getTranslatedFieldSupport().parse(this, value); //用validators来验证值 getValidatableFieldSupport().validate(this, writer, cycle, object); //赋值给容器或者页面 setValue(object); } catch (ValidatorException e) { getForm().getDelegate().record(e); } }
可以看到在rewindFormComponent中,主要是从请求中取得用户输入的值,然后进行处理,最后赋值给容器或者页面,上面的例子中会调用页面类的getPicture().setPrice(“用户输入的值”)来进行赋值。这样整个表单的提交就可以理解为所有的表单组件读取用户输入的值并赋值给页面的过程。
整个表单提交的详细处理过程如下:
- * initialize():页面初始化
* pageBeginRender() ("rewind"):getRequestCycle().isRewinding()为true
* rewind of the form / setting of properties:所有表单组件调用rewindFormComponent来取值赋值
* Deferred listeners (for Submit components):调用Submit组件的listener
* Form's listener:调用Form组件的listener
* pageEndRender() ("rewind"): getRequestCycle().isRewinding()为true
* pageBeginRender() (normal): getRequestCycle().isRewinding()为false
* pageEndRender() (normal): getRequestCycle().isRewinding()为false
public abstract void setPictures(List<Picture> pictures); public abstract void setPictureInList();//用于For中的value public abstract void setPicture(Picture picture);//用于表单创建 public abstract Picture getPicture(); public void pageBeginRender(PageEvent event) { if(getPicture()==null){ setPicture(new Picture()); } setPictures(getPictureService().findAll()); }判断picture是否为null并赋值在页面显示和rewind中都是需要的,因为页面显示时,需要调用getPicture().getPrice(),页面rewind时,需要调用getPicture().setPrice(),这两个阶段中的picture都不能为null。但setPictures会在表单提交时被调用两次,在rewind阶段初始化它是没有用处的,所以这时就要对是否rewind进行判断。修改后的代码如下:
public void pageBeginRender(PageEvent event) { if(getPicture()==null){ setPicture(new Picture()); } if (!event.getRequestCycle().isRewinding()) { setPictures(getPictureService().findAll()); } }这样就可以避免在rewind时对pictures进行不必要的赋值。这里还要提到的一点是页面显示和提交后的页面很可能不是同一个页面类的实例,大家都知道页面类的实例是从实例池取到的,用户打开页面显示表单完后的页面类实例和用户提交表单时的用来rewind的页面类实例不一定是同一个,即使是一个实例,也是被重新初始化过的,不要想当然的认为显示表单后再提交那个实例应该保存原来显示的东西,这个应该理清楚。
上一篇: Tapestry4常用的注入对象
推荐阅读