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

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

   
   
   
   
java 代码
 
  1. public ILink listenerMethod(Parameter parameter); 

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

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.   }  

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

页面类继承MyBasePage,这样就可以使用上述方法了。

这样在页面提交时可以如下调用
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. }  

然后写注释的worker

   
   
   
   
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
的同样两个类
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. }  

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. }  
类写好了,然后就是贡献到Tapestry
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>  

好了将你的module放入项目hivemodule.Xml作为子module
Ok enjoy it

 

你可能感兴趣的:(Tapestry,设计模式,Apache,OO,Ajax)