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

在Tapestry中使用redirect-after-post模式控制表单提交

阅读更多
Tapestry中表单的提交有很多问题,刷新导致表单的重复提交、臭名昭著的dirty form warning
显示不友好的URL等,这些都可以使用redirect-after-post模式来避免,也就是post表单之后将页面redirect一下,
这样地址栏显示的就是
redirect之后的页面,刷新的也将是这个页面,而且redirect之后的页面一般为Page页面,
可以使用
friendlyUrl来显示友好的url<o:p></o:p>
要使用这个模式,不得不提到一个ILink接口,T4中可接受的listener方法中一个方法签名是这样的:<o:p></o:p>
java 代码
 
  1. public ILink listenerMethod(Parameter parameter); 

这个方法的返回值为ILink,如果T4侦测到是这个返回值的话,将自动redirectILink指定的页面。
而且
ILink可以为纯页面的Link也可以是带有参数的Link。纯页面Link也就是page service生成的link
带参数的
linkexternal service生成的link,具体link的生成代码如下:<o:p></o:p>  

java 代码
 
  1. @InjectObject("engine-service:page")  
  2.   
  3.   public abstract IEngineService getPageService();  
  4.   
  5.        public ILink getPageLink(String pageName) {  
  6.   
  7.            return getPageService().getLink(false, pageName);  
  8.   
  9.   }  
  10.   
  11.   
  12.   
  13.       @InjectObject("engine-service:external")  
  14.   
  15.   public abstract IEngineService getExternalService();  
  16.   
  17.        public ILink getExternalLink(String pageName, Object[] parameters) {  
  18.   
  19.      ExternalServiceParameter esp = new ExternalServiceParameter(pageName,  
  20.   
  21.             parameters);  
  22.   
  23.      return getExternalService().getLink(false, esp);  
  24.   
  25.   }  
<o:p></o:p>

将上述方法放入到你的项目中自定义的MyBasePage(继承TapestryBasePage)中,然后让你的

页面类继承MyBasePage,这样就可以使用上述方法了。<o:p></o:p>

这样在页面提交时可以如下调用
java 代码
 
  1. public ILink onDelete(Long id){  
  2.   
  3.    
  4.   
  5. //your code to delete object  
  6.   
  7.    
  8.   
  9. return getPageLink(getPageName());//删除后重新redirect到本页面  
  10.   
  11. }  
  12.   
  13. 当然如果这个页面带参数,例如catgoryId=1,则代码如下:  
  14.   
  15. public ILink onDelete(Long id){  
  16.   
  17.    
  18.   
  19. //your code to delete object  
  20.   
  21.    
  22.   
  23. return getExternalLink(getPageName(),new Object[]{categoryId});  
  24. //删除后重新redirect到本页面,并带一个参数  
  25.   
  26. }  
上述方式通过继承来实现方法调用,感觉不是很好,我们可以利用Tapestry的易扩展特性来扩展它,
首先想到的就是注释方式来注入,例如我想实现如下注入
java 代码
 
  1. @InjectPageLink(“Home“)  
  2.   
  3. Public abstract ILink getHomeLink();  
  4.   
  5.    
  6.   
  7. @InjectExternalLink(“Category“)  
  8.   
  9. Public abstract ILink getCategoryLink(Long categoryId);  

这样即去掉了页面的继承,也显得比较直接。
首先是定义注释类
java 代码
 
  1. import java.lang.annotation.ElementType;  
  2.   
  3. import java.lang.annotation.Retention;  
  4.   
  5. import java.lang.annotation.RetentionPolicy;  
  6.   
  7. import java.lang.annotation.Target;  
  8.   
  9.    
  10.   
  11. @Target( { ElementType.METHOD })  
  12.   
  13. @Retention(RetentionPolicy.RUNTIME)  
  14.   
  15. public @interface InjectPageLink {  
  16.   
  17.     String value();  
  18.   
  19. }  

<o:p></o:p>

然后写注释的worker
<o:p></o:p>
java 代码
 
  1. import java.lang.reflect.Method;  
  2.   
  3. import java.lang.reflect.Modifier;  
  4.   
  5.    
  6.   
  7. import org.apache.hivemind.ApplicationRuntimeException;  
  8.   
  9. import org.apache.hivemind.Location;  
  10.   
  11. import org.apache.hivemind.service.BodyBuilder;  
  12.   
  13. import org.apache.hivemind.service.MethodSignature;  
  14.   
  15. import org.apache.tapestry.annotations.AnnotationUtils;  
  16.   
  17. import org.apache.tapestry.annotations.MethodAnnotationEnhancementWorker;  
  18.   
  19. import org.apache.tapestry.engine.ILink;  
  20.   
  21. import org.apache.tapestry.enhance.EnhancementOperation;  
  22.   
  23. import org.apache.tapestry.spec.IComponentSpecification;  
  24.   
  25.    
  26.   
  27. public class InjectPageLinkAnnotationWorker implements  
  28.   
  29.        MethodAnnotationEnhancementWorker {  
  30.   
  31.    
  32.   
  33.     public void performEnhancement(EnhancementOperation op,  
  34.   
  35.            IComponentSpecification spec, Method method, Location location) {  
  36.   
  37.        if (!method.getReturnType().equals(ILink.class))  
  38.   
  39.            throw new ApplicationRuntimeException(  
  40.   
  41.                   "InjectPage annotation must return ILink");  
  42.   
  43.    
  44.   
  45.        InjectPageLink injectPageLink = method  
  46.   
  47.               .getAnnotation(InjectPageLink.class);  
  48.   
  49.    
  50.   
  51.        String pageName = injectPageLink.value();  
  52.   
  53.    
  54.   
  55.        BodyBuilder builder = new BodyBuilder();  
  56.   
  57.    
  58.   
  59.        builder.begin();  
  60.   
  61.        builder  
  62.   
  63.               .addln(  
  64.   
  65.                      "return getPage().getRequestCycle().getInfrastructure().getServiceMap().getService( 
  66.  
  67. org.apache.tapestry.Tapestry.PAGE_SERVICE).getLink(false,\"{0}\");",  
  68.   
  69.                      pageName);  
  70.   
  71.    
  72.   
  73.        builder.end();  
  74.   
  75.    
  76.   
  77.        op.addMethod(Modifier.PUBLIC, new MethodSignature(method), builder  
  78.   
  79.               .toString(), location);  
  80.   
  81.    
  82.   
  83.        if (isGetter(method))  
  84.   
  85.            op.claimReadonlyProperty(AnnotationUtils.getPropertyName(method));  
  86.   
  87.     }  
  88.   
  89.    
  90.   
  91.     boolean isGetter(Method method) {  
  92.   
  93.        return method.getName().startsWith("get")  
  94.   
  95.               && method.getParameterTypes().length == 0;  
  96.   
  97.     }  
  98.   
  99. }  

External
的同样两个类<o:p></o:p>
java 代码
 
  1. import java.lang.annotation.ElementType;  
  2.   
  3. import java.lang.annotation.Retention;  
  4.   
  5. import java.lang.annotation.RetentionPolicy;  
  6.   
  7. import java.lang.annotation.Target;  
  8.   
  9.    
  10.   
  11. @Target( { ElementType.METHOD })  
  12.   
  13. @Retention(RetentionPolicy.RUNTIME)  
  14.   
  15. public @interface InjectExternalLink {  
  16.   
  17.     String value();  
  18.   
  19. }  

<o:p></o:p>

Work
java 代码
 
  1. import java.lang.reflect.Method;  
  2.   
  3. import java.lang.reflect.Modifier;  
  4.   
  5.    
  6.   
  7. import org.apache.hivemind.ApplicationRuntimeException;  
  8.   
  9. import org.apache.hivemind.Location;  
  10.   
  11. import org.apache.hivemind.service.BodyBuilder;  
  12.   
  13. import org.apache.hivemind.service.MethodSignature;  
  14.   
  15. import org.apache.tapestry.Tapestry;  
  16.   
  17. import org.apache.tapestry.annotations.AnnotationUtils;  
  18.   
  19. import org.apache.tapestry.annotations.MethodAnnotationEnhancementWorker;  
  20.   
  21. import org.apache.tapestry.engine.ILink;  
  22.   
  23. import org.apache.tapestry.enhance.EnhancementOperation;  
  24.   
  25. import org.apache.tapestry.spec.IComponentSpecification;  
  26.   
  27.    
  28.   
  29. public class InjectExternalLinkAnnotationWorker implements  
  30.   
  31.        MethodAnnotationEnhancementWorker {  
  32.   
  33.    
  34.   
  35.     public void performEnhancement(EnhancementOperation op,  
  36.   
  37.            IComponentSpecification spec, Method method, Location location) {  
  38.   
  39.        if (!method.getReturnType().equals(ILink.class))  
  40.   
  41.            throw new ApplicationRuntimeException(  
  42.   
  43.                   "injectExternalLink annotation must return ILink");  
  44.   
  45.    
  46.   
  47.        InjectExternalLink injectExternalLink = method  
  48.   
  49.               .getAnnotation(InjectExternalLink.class);  
  50.   
  51.    
  52.   
  53.        String pageName = injectExternalLink.value();  
  54.   
  55.    
  56.   
  57.        BodyBuilder builder = new BodyBuilder();  
  58.   
  59.    
  60.   
  61.        builder.begin();  
  62.   
  63.    
  64.   
  65.        Class[] parameterTypes = method.getParameterTypes();  
  66.   
  67.        int paramCount = Tapestry.size(parameterTypes);  
  68.   
  69.    
  70.   
  71.        if (paramCount > 0) {  
  72.   
  73.            if (parameterTypes[0].isArray()) {  
  74.   
  75.               builder  
  76.   
  77.                      .addln(  
  78.   
  79.                             "return getPage().getRequestCycle().getInfrastructure().getServiceMap(). 
  80.  
  81. getService(org.apache.tapestry.Tapestry.EXTERNAL_SERVICE).getLink(false, new org.apache.tapestry.engine.ExternalServiceParameter(\"{0}\",$1));",  
  82.   
  83.                             pageName);  
  84.   
  85. else {  
  86.   
  87.               builder  
  88.   
  89.                      .addln(  
  90.   
  91.                             "java.lang.Object[] params = new java.lang.Object[{0}];",  
  92.   
  93.                             paramCount);  
  94.   
  95.               for (int i = 0; i < paramCount; i++) {  
  96.   
  97.                   builder.add("params[{0}] = ", i);  
  98.   
  99.    
  100.   
  101.                   if (parameterTypes[i].isPrimitive())  
  102.   
  103.                      builder.add("($w) ");  
  104.   
  105.    
  106.   
  107.                   // Parameter $0 is this, so $1 is the first real parameter.  
  108.   
  109.    
  110.   
  111.                   builder.addln("${0};", i + 1);  
  112.   
  113.               }  
  114.   
  115.               builder  
  116.   
  117.                      .addln(  
  118.   
  119.                             "return getPage().getRequestCycle().getInfrastructure().getServiceMap().getService(org.apache.tapestry.Tapestry.EXTERNAL_SERVICE).getLink(false, new org.apache.tapestry.engine.ExternalServiceParameter(\"{0}\",params));",  
  120.   
  121.                             pageName);  
  122.   
  123.            }  
  124.   
  125.        }  
  126.   
  127.    
  128.   
  129.        builder.end();  
  130.   
  131.    
  132.   
  133.        op.addMethod(Modifier.PUBLIC, new MethodSignature(method), builder  
  134.   
  135.               .toString(), location);  
  136.   
  137.    
  138.   
  139.        if (isGetter(method))  
  140.   
  141.            op.claimReadonlyProperty(AnnotationUtils.getPropertyName(method));  
  142.   
  143.     }  
  144.   
  145.    
  146.   
  147.     boolean isGetter(Method method) {  
  148.   
  149.        // We already know the return type is String  
  150.   
  151.    
  152.   
  153.        return method.getName().startsWith("get")  
  154.   
  155.               && method.getParameterTypes().length == 0;  
  156.   
  157.     }  
  158.   
  159. }  
<o:p></o:p>
类写好了,然后就是贡献到Tapestry<o:p></o:p>
xml 代码
 
  1. <module id="your.model.annotation" version="1.0.0" package="your.package.annotations">  
  2.   
  3.      <contribution configuration-id="tapestry.annotation.MethodWorkers">  
  4.   
  5.       <worker annotation="InjectPageLink" object="instance:InjectPageLinkAnnotationWorker"/>  
  6.   
  7.       <worker annotation="InjectExternalLink" object="instance:InjectExternalLinkAnnotationWorker"/>  
  8.   
  9.     <!---->contribution>  
  10.   
  11. <!---->module>  

<o:p></o:p>
好了将你的module放入项目hivemodule.Xml作为子module<o:p></o:p>
Okenjoy it

<o:p></o:p>

<o:p> </o:p>

分享到:
评论
6 楼 cgc520 2007-06-11  
我无语.
5 楼 tapestry 2006-12-18  
InjectPageLink和InjectExternalLink已经提交到tapestry的jira中,将集成到4.1.2版本中,呵呵,也算对开源做了贡献。

详细信息:
http://issues.apache.org/jira/browse/TAPESTRY-1184?page=history
4 楼 vlinux 2006-12-04  
太好了,mark,我前一段时间正在想解决这样的问题呢
不过现在先不能看,等考完SCJP和学期末考试再说
3 楼 zhangqidi 2006-11-29  
说到根本上,是概念不一致造成的问题。<br/>
<br/>
从web来看,url本身是一种uri,用于资源定位。但是从web开发实践看来,更多的把他作为web api的包装器。这种冲突,在ajax应用方面也有体现。<br/>
<br/>
url做为uri,被设计为没有状态的,但是做为api,就会有状态。如果不能让那些设计标准的专业人士认识到这种差距,那么这种尴尬总会存在。
2 楼 tapestry 2006-11-29  
是呀,tapestry的经典处理流程就是get page->set state->active
active调用的是forward方法,就是当前页面的实际页面与url上指示的页面不相符,这也无可厚非。tapestry如果真的要完全的OO的话,屏蔽URL上的处理是必须的。
取得ILink来redirect的一个好处是可以防止form提交后refresh。
1 楼 zhangqidi 2006-11-29  
不错,又学到了新东西。<br/>
<br/>
不过,就应用上讲,我的处理方式跟楼主提到的不一样。<br/>
<br/>
一是listener方法返回void,自己用cycle来激活。看起来直接。<br/>
如果仅仅是跳转,直接激活。如果需要refresh,直接通过ILink抛出异常算了。<br/>
<br/>
二是不太看好这种refresh的实际价值。<br/>
我的使用经验是,listener方法是对application中的page和component状态进行控制、设置和初始化的重要环节,如果 refresh掉,那么状态就丢失了,重新找状态很费事。这个listener就失去相当的价值。如果页面状态很简单,这倒是ok。但是如果状态复杂,就几乎没有这种可能性了。<br/>
<br/>
根本原因,是因为url是service调用接口的表现,而不是service如何执行的表现。这可能是没有办法的事情。记得胡子老大自己也说过,跟其他框架比起来,要追求漂亮的url,在tapestry里面奋战没有胜算。<br/>
<br/>
<br/>
<br/>
<br/>
<br/>

相关推荐

    tapestry-bin-5.1.0.5

    8. **tapestry-hibernate-NOTICE.txt, tapestry-hibernate-core-NOTICE.txt, tapestry-ioc-NOTICE.txt**:与对应的LICENSE文件类似,这些NOTICE文件列出了在Tapestry的这些特定模块中使用到的第三方组件和它们的版权...

    tapestry-project-4.1.5

    在"tapestry-project-4.1.5"这个压缩包中,我们有机会深入探索 Tapestry 4.1.5 版本的特性和应用。 首先,让我们关注"Tapestry-libraries"这个文件夹。它包含了Tapestry 框架运行所需的各种库文件,这些库文件是...

    apache-tapestry-5.3.7-bin.zip

    `tapestry-jpa-5.3.7.jar`和`tapestry-hibernate-5.3.7.jar`则与持久层集成有关,它们支持JPA(Java Persistence API)和Hibernate ORM框架,使开发者能够轻松地在Tapestry应用中处理数据库操作。 总的来说,Apache...

    apache-tapestry-5.3.8-bin.zip

    11. **Tapestry Hibernate**:`tapestry-hibernate-5.3.8.jar`是Tapestry与Hibernate集成的库,提供了在Tapestry应用中使用Hibernate的相关工具和服务。 通过这个发行包,开发者可以快速搭建Tapestry环境,开发基于...

    优化大使tapestry-bin-5.0.18.zip

    在本案例中,"tapestry-bin-5.0.18.zip" 是一个与 Tapestry 框架相关的压缩包,这可能是一个用于Web应用开发的工具集或库。Tapestry 是一个开源的Java Web应用程序框架,由Apache软件基金会维护,它允许开发者以组件...

    tapestry-bin-5.0.14.zip

    - “tapestry-hibernate”是Tapestry与Hibernate集成的模块,使开发者能够方便地在Tapestry应用中使用Hibernate进行对象关系映射(ORM)操作。 - “tapestry-ioc”是Tapestry的依赖注入(IOC)容器,它简化了服务和...

    tapestry-ioc-5.0.3-src

    在"tapestry-ioc-5.0.3-src"这个压缩包中,我们可能找到Tapestry IOC框架的源代码,这对于开发者深入理解其工作原理和定制功能非常有价值。 1. **依赖注入(DI)**:Tapestry IOC的核心概念就是DI,它允许对象在...

    Tapestry4.1.2 入门-介绍

    这些组件可以通过简单的XML标记(如`&lt;span jwcid="@Insert" ...&gt;`)在页面模板中使用。ognl(Object-Graph Navigation Language)则用于在组件间传递数据和表达式计算。 此外,Tapestry还提供了诸如页面转换、错误...

    tapestry教程资料文档合集

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

    Tapestry-3-Getting Started.doc

    - **项目名称**:Tapestry-3-Getting Started - **项目目标**:开发一个基于Web的货币转换器应用。 - **技术栈**:Tapestry 3、Eclipse IDE、Apache Tomcat。 #### 二、开发环境搭建 ##### 1. Eclipse IDE安装 - **...

    tapestry-spring-5.2.6.jar

    tapestry-spring-5.2.6.jar,java spring框架依赖,可以直接使用

    tapestry官方中文文档

    在Tapestry中,大多数的编程都是声明式的,这意味着开发者可以使用XML或注解来定义页面和组件的行为,而不是编写大量的Java代码。这降低了代码的复杂性,提高了可读性和维护性。 4. **页面和组件生命周期**: ...

    tapestry-4.0.zip

    Tapestry 是一个开源的Java Web应用程序框架,由Apache软件基金会维护。这个“tapestry-4.0.zip”...这个“tapestry-4.0.zip”压缩包中的内容,包含了一系列源码、文档和示例,是深入研究Tapestry 4.0的宝贵资源。

    tapestry 5.3中文教程

    - 使用 `@SessionState` 注解在会话中存储数据。 - 示例代码: `@SessionState private User user;` - **JavaScript 集成**: - 通过 `@JavaScript` 注解引入 JavaScript 脚本。 - 示例代码: `@JavaScript("script...

    tapestry5 build web application-alexander

    通过阅读此书,读者能够深入理解Tapestry 5如何将MVC(模型-视图-控制器)模式与组件编程思想结合,实现高度模块化和可重用的Web应用设计。 1. **组件模型**:Tapestry 5的核心是组件模型,它允许开发者创建可复用...

    tapestry-src-5.1.0.5.zip

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

    Tapestry-3.0.4-bin.zip

    这个是开发tapestry3所用的JAR包

Global site tag (gtag.js) - Google Analytics