`
tapestry
  • 浏览: 187038 次
社区版块
存档分类
最新评论

深入理解Tapestry的Rewind

阅读更多
Tapestry的rewind一直是学习和使用Tapestry的难点,rewind是用来处理表单提交的,表单默认使用的是DirectService来提交。在详细介绍之前,先说明下此文中需要用到的一些概念,首先是表单组件,我这里指的是指继承自AbstractFormComponent类的组件,例如:TextField、TextArea、Checkbox等,而不是具体的Form组件,表单组件使用时必须在Form组件中,这些组件在rewind时调用继承自AbstractFormComponent的rewindFormComponent来读取数据,并将数据赋值给容器或者页面。
我们来看一下最简单的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
我们可以看到pageBeginRender和pageEndRender被调用了两次,两次中的区别为RequestCycle().isRewinding,因为我们在使用时经常利用pageBeginRender的初始化值,所以这里有很多使用上的误区,如果在pageBeginRender中从数据库读取数据来初始化跟表单提交无关的变量的话,就可能被调用两次,这个是应该避免的。什么叫跟表单提交无关的变量呢,就是表单组件中跟赋值无关的,例如上边提到的value="ognl:picture.price",这时picture就是与表单提交相关的变量,如果你没有初始化,那么在赋值时调用getPicture().setPrice()就会出现空指针异常,因为这是的picture为null。我们举个例子来看一下表单无关的变量,假如这个picture页面会显示一个创建picture的表单和所有picture的列表,那这个picture的列表就是与表单提交无关的变量,如果你在pageBeginRender中初始化的话,就需要区分是否rewind,否则表单提交时就会被初始化两次,让我们看一下代码:
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的页面类实例不一定是同一个,即使是一个实例,也是被重新初始化过的,不要想当然的认为显示表单后再提交那个实例应该保存原来显示的东西,这个应该理清楚。
分享到:
评论
12 楼 tapestry 2007-04-24  
所以要加上判断event.getRequestCycle().isRewinding(),rewind是好是坏一直都是有争议的,你可以参考这篇文章
http://nate-tech.blogspot.com/2006/01/why-tapestrys-crazy-rewind-is-good.html
11 楼 ellie4c 2007-04-23  
刚看了原代码 发现确实是执行2次 一次是在Form 的rewind里面 一次在Service 的service 方法里面调用_responseRenderer.renderResponse(cycle);但是这样的话我每次用到pageRender的时候不是都要很小心的 提醒自己是否页面里面会有form提交产生2次解析的问题了吗?这样会不会很累:)
10 楼 tapestry 2007-04-23  
文章表达的是从一个request到response整个提交流程,这个流程中包含rewindForm,而不是单独说rewindForm这个流程,rewindForm里调用了page.beginPageRender();,在rewindForm之后,页面会重新render一次的。
9 楼 ellie4c 2007-04-22  
我没看懂 为什么在rewindForm的时候会执行2次PageBeginRender哪?应该还是一次呀,只是在我门需要在这种情况考率到是否是2次解析的问题.
public void rewindForm(IForm form)

try
436            {
437                page.beginPageRender();
438   
439                form.rewind(NullWriter.getSharedInstance(), this);
440   
441                // Shouldn't get this far, because the form should
442                // throw the RenderRewoundException.
443   
444                throw new StaleLinkException(Tapestry.format("RequestCycle.form-rewind-failure", form
445                        .getExtendedId()), form);
446            }
447            catch (RenderRewoundException ex)
448            {
449                // This is acceptible and expected.
450            }
451            catch (ApplicationRuntimeException ex)
452            {
453                // RequestCycleExceptions don't need to be wrapped.
454                throw ex;
455            }
456            catch (Throwable ex)
457            {
458                // But wrap other exceptions in a ApplicationRuntimeException ... this
459                // will ensure that some of the context is available.
460   
461                throw new ApplicationRuntimeException(ex.getMessage(), page, null, ex);
462            }
463            finally
464            {
465                page.endPageRender();
466   
467                _monitor.pageRewindEnd(pageName);
468   
469                reset();
470                _rewinding = false;
471            }
代码上写的很清楚,应该是一次吧,对T我不是很理解,请
8 楼 Ghostbb 2007-04-05  
搂主方便讲解一下Tapestry启动时候服务加载的顺序吗?一切都是从哪里开始的呢?
7 楼 drumdance 2007-03-12  
好文 讲的很清晰 评论也精彩!
能学到真东西
6 楼 andy020118 2007-01-14  
5 楼 andy020118 2007-01-14  
[color=red][/color] [size=7][/size]
4 楼 lkyooo 2007-01-07  
创建页面的时候是调用initialize(),然后再执行其它的操作,我没有从最初的流程来看,是从存在的页面以rewind的这个过程来考虑,Sorry,以后有问题还要多多请教前辈:)
3 楼 tapestry 2007-01-07  
整个流程不是说从池中取出后,响应请求的,只是说明流程。如果还没有创建这个页面的池,那它会创建这个页面,并响应请求,然后放入池中,那创建时会调用initialize()方法。
源代码:
/**
* Standard constructor; invokes {@link #initialize()}to configure initial values for
* properties of the page.
*
* @since 2.2
*/

public AbstractPage() {
initialize();
}
2 楼 lkyooo 2007-01-07  
有一个地方没有写对
initialize():页面初始化
是在页面放入池中之前,AbstractPage中的detach方法(解除页面和engine之类的东西的attach)调用的,而不是在页面从池中取出的时候。
public void detach()
    {
        Tapestry.addMethodInvocation(Tapestry.ABSTRACTPAGE_DETACH_METHOD_ID);

        // Do this first,so that any changes to persistent properties do not
        // cause errors.

        _changeObserver = null;

        firePageDetached();

        initialize();

        _engine = null;
        _visit = null;
        _requestCycle = null;
    }
1 楼 wrong1111 2006-12-31  
写得不错!! 支持多写一点,学习。。。。。

相关推荐

    tapestry 源码 深入研究tapestry最好资料

    tapestry 源码 深入研究tapestry最好资料

    深入浅出Tapestry

    资源名称:深入浅出Tapestry内容简介:本书以循序渐进的方式,从Tapestry框架技术的基本概念入手,讲解Tapestry框架在J2EE Web应用程序中的整体架构实现。使读者在学习如何使用Tapestry框架技术的同时,还能够获得在...

    深入浅出tapestry

    本书以循序渐进的方式,从Tapestry框架技术的基本概念入手,讲解Tapestry框架在J2EE Web应用程序中的整体架构实现。使读者在学习如何使用Tapestry框架技术的同时,还能够获得在J2EE Web应用程序中应用Tapestry框架的...

    深入浅出Tapestry4一书源代码(1)

    深入浅出Tapestry4一书源代码 需要自己调试

    深入浅出Tapestry4一书源代码(2)

    Tapestry4 Tapestry4 深入浅出Tapestry4深入浅出Tapestry4深入浅出Tapestry4

    深入浅出Tapestry高清

    深入浅出Tapestry高清版电子书,国内Tapestry权威人士撰写,中文唯一的Tapestry书籍材料。

    tapestry教程资料文档合集

    Tapestry5最新中文教程.doc 作者 Renat Zubairov & Igor Drobiazko译者 沙晓兰 发布于 2008年7月2日 下午9时30分 社区 Java 主题 Web框架 ----------------------------------------- Tapestry5.1实例教程.pdf ...

    Tapestry4开发指南.rar

    Tapestry4开发指南.rar

    tapestry5以上的帮助事例,帮助文档与spring衔接文档

    Tapestry是一个基于控件的框架以致于用它开发Web应用类似开发传统的GUI应用。你用Tapestry开发Web应用时你无需关注以操作为中心的(Operation-centric) Servlet API.引用Tapestry网站上的一句话:"Tapestry用对象...

    tapestry官方中文文档

    Tapestry 4 官方文档中文版本,现在中文资料比较少,和大家共享一下

    tapestry 实例

    tapestry 实例tapestry 实例tapestry 实例tapestry 实例

    Tapestry5.0.16_API文档

    Tapestry5.0.16文档和大家一起学习

    tapestry3开发指南,带tapestry3所有jar包

    tapestry3开发指南,带tapestry3所有jar包

    Tapestry5最新中文入门实例教程

    本文介绍Tapestry框架版本5。本文利用Tapestry 5开发一个简单的具有创建/读/更新/删除功能的应用,在创建这个应用的过程中,本文体会到Tapestry...还将了解如何应用Tapestry中内嵌的Ajax功能来创建支持Ajax的组件。

    Tapestry4开发指南

    Tapestry4开发指南

    tapestry5.2.6 jar包

    tapestry5.2.6 最新jar包,Tapestry框架是一个位于java servlet容器和Tapestry应用程序之间的层

    tapestry技术

    tapestry技术 Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得...

    tapestry-src-5.1.0.5.zip

    包含: tapestry 的源代码, tapestry集成spring2.0 tapestry快速启动 tapestry upload tapestry hibernate tapestry annotations

    Tapestry开发指南

    Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得java代码与html...

Global site tag (gtag.js) - Google Analytics