wicket tapestry5 sopo 模板实现浅析

1 Wicket实现

      Wicket模板是html格式,示例:index.html
Html代码

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
  2. <html> 
  3. <head> 
  4.    <title>Index.html</title> 
  5.    
  6.    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 
  7.    <meta http-equiv="description" content="this is my page"> 
  8.    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> 
  9.    
  10.    <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> 
  11.  
  12. </head> 
  13.  
  14. <body>  
  15.    <a wicket:id="edit" href="UserEdit.html?uid=1" target="_blank" >edit form</a> 
  16. </body> 
  17. </html> 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
   <title>Index.html</title>
  
   <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
   <meta http-equiv="description" content="this is my page">
   <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  
   <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

</head>

<body>
   <a wicket:id="edit" href="UserEdit.html?uid=1" target="_blank" >edit form</a>
</body>
</html>


还要在后台page类Index 中手动添加进组件列表中。
Java代码

  1. public class Index extends WebPage 
  2. /**
  3. * Constructor
  4. */ 
  5. public Index() 
  6.    PageLink link = new PageLink("edit",new IPageLink()); 
  7.    add(link); 

public class Index extends WebPage
{
/**
* Constructor
*/
public Index()
{
   PageLink link = new PageLink("edit",new IPageLink());
   add(link);
}
}


add方法是继承自父类org.apache.wicket.MarkupContainer的方法会将组件添加到其字段children中去.
模板由org.apache.wicket.markup.MarkupParser解析,遇到wicket:id属性的会转换为org.apache.wicket.markup.MarkupElement,
最终将html模板解析成MarkupElement列表,添加到org.apache.wicket.markup.MarkupList<MarkupElement> markupElements集合中,在组件绘制的时候,将其
包装成org.apache.wicket.markup.MarkupStream,会遍历MarkupElement列表,依据组件id获得组件,让每个组件进行绘制--调用方法
void org.apache.wicket.Component.render(MarkupStream markupStream).
具体的主要的解析实现是由org.apache.wicket.markup.parser.XmlPullParser完成的,通过过字符串操作来解析,详见其next方法,并没有使用第三方类库.
2 tapestry实现
       tapestry5模板时xml格式,示例Index.tml
Html代码

  1. <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> <head> 
  2. <title>Test</title> 
  3. </head> 
  4. <body> 
  5. <h1>Test</h1> 
  6. <h1>Address Book</h1> 
  7. <t:span c="d" >${fi}</t:span> 
  8. <ul> 
  9. <li> 
  10. <a t:type="pagelink" t:page="index" >Create new address</a> 
  11. </li> 
  12. </ul> 
  13. </body> </html> 

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> <head>
<title>Test</title>
</head>
<body>
<h1>Test</h1>
<h1>Address Book</h1>
<t:span c="d" >${fi}</t:span>
<ul>
<li>
<a t:type="pagelink" t:page="index" >Create new address</a>
</li>
</ul>
</body> </html>


因为已经在模板中指明了这个节点是什么类型的组件,所以,tapestry5就不需要再add组件了,它本身也不提供add方法。       
public class Index
Java代码

  1. @Inject 
  2. private Logger logger; 
  3. private GridDataSource dss; 
  4. private int fi; 
  5. public Index() 
  6. super(); 
  7. System.out.println("call ctor."); 
  8. public int getFi() 
  9. return fi; 
  10. public void setFi(int fi) 
  11. this.fi = fi; 

{
@Inject
private Logger logger;
private GridDataSource dss;
private int fi;
public Index()
{
super();
System.out.println("call ctor.");
}
public int getFi()
{
return fi;
}
public void setFi(int fi)
{
this.fi = fi;
}
}


           tapastry5使用stAx实现的,这篇文章介绍了stax的用法,tapestry5通过注入的方式将org.apache.tapestry5.internal.services.TemplateParserImpl注入到                                            
           org.apache.tapestry5.internal.services.ComponentTemplateSourceImpl中的private final TemplateParser parser;字段中,TemplateParserImpl
           实际使用的是org.apache.tapestry5.internal.services.StaxTemplateParser,在这里面会使用stax对模板进行解析。它通过节点是否有t:id,t:type属性来判断
           是否是一个服务端组件。解析完模板会组建成一个节点列表,再在绘制页面的时候依据这个列表的顺序来调用相应的组件绘制。
           逻辑主要在以下的类中
           org.apache.tapestry5.internal.parser.ComponentTemplateImpl
           org.apache.tapestry5.internal.structure.PageImpl
           org.apache.tapestry5.internal.services.PageRenderRequestHandlerImpl
           org.apache.tapestry5.internal.services.PageResponseRendererImpl
           org.apache.tapestry5.internal.services.PageMarkupRendererImpl
           org.apache.tapestry5.internal.services.PageRenderQueueImpl
           Page org.apache.tapestry5.internal.pageload.PageLoaderImpl.loadPage(String logicalPageName, Locale locale)

3 sopo的实现方法

     Sopo是可由每个page类来指明模板内容,只要是html格式就可以,示例:

Html代码

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
  2. <html> 
  3. <head> 
  4.    <title>test.html</title> 
  5.    
  6.    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 
  7.    <meta http-equiv="description" content="this is my page"> 
  8.    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> 
  9.    
  10.    <link rel="stylesheet" type="text/css" href="./styles.css"> 
  11.    <script type="text/javascript" src="js/hello.js" ></script> 
  12.    <script type="text/javascript"> 
  13.       function $(id){ 
  14.           return document.getElementById(id); 
  15.       } 
  16.       function test() 
  17.       { 
  18.           $('rst').innerHTML=reg.test($('d').value); 
  19.       } 
  20.       var reg = new RegExp("^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$"); 
  21.       //var reg = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/i; 
  22.    </script> 
  23. </head> 
  24.  
  25. <body> 
  26. h-------- 
  27. <!-- hahah  --> 
  28.    <![CDATA[jkjkjk]]> 
  29.    <form action=""> 
  30.    <label stype="s:Label" id="lab1" >Hello World1<label stype="s:Label" id="lab2" >Hello World3</label></label> 
  31.    <input type="password" />    
  32.    <label stype="s:Label" id="lab3" >Hello World2</label> 
  33.    <input stype="s:Checkbox" id="chk" name="chk" >sss</input> 
  34.    <select stype="s:Select" id="sel" name="sel" width="20px" > 
  35.        <option stype="s:Option" text="1" ></option> 
  36.        <option stype="s:Option" text="2" selected="selected" ></option> 
  37.        <option stype="s:Option" text="3" ></option> 
  38.    </select>      
  39.    <input id="d" type="text" /><button onclick="test();">Test</button> 
  40.    <span id="rst">true</span> 
  41.    <input type="radio" name="1" >1</input> 
  42.    <input type="radio" name="1" >2</input> 
  43.    <input type="radio" name="1" onclick="alert(this.value);" >3</input>3 
  44.    </form> 
  45. </body> 
  46. </html> 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
   <title>test.html</title>
  
   <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
   <meta http-equiv="description" content="this is my page">
   <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  
   <link rel="stylesheet" type="text/css" href="./styles.css">
   <script type="text/javascript" src="js/hello.js" ></script>
   <script type="text/javascript">
      function $(id){
          return document.getElementById(id);
      }
      function test()
      {
          $('rst').innerHTML=reg.test($('d').value);
      }
      var reg = new RegExp("^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$");
      //var reg = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/i;
   </script>
</head>

<body>
h--------
<!-- hahah  -->
   <![CDATA[jkjkjk]]>
   <form action="">
   <label stype="s:Label" id="lab1" >Hello World1<label stype="s:Label" id="lab2" >Hello World3</label></label>
   <input type="password" />   
   <label stype="s:Label" id="lab3" >Hello World2</label>
   <input stype="s:Checkbox" id="chk" name="chk" >sss</input>
   <select stype="s:Select" id="sel" name="sel" width="20px" >
       <option stype="s:Option" text="1" ></option>
       <option stype="s:Option" text="2" selected="selected" ></option>
       <option stype="s:Option" text="3" ></option>
   </select>     
   <input id="d" type="text" /><button onclick="test();">Test</button>
   <span id="rst">true</span>
   <input type="radio" name="1" >1</input>
   <input type="radio" name="1" >2</input>
   <input type="radio" name="1" onclick="alert(this.value);" >3</input>3
   </form>
</body>
</html>


它和tapestry有些像,因为模板里面指明了组件类型,所以就不需要再添加了.
Java代码

  1. public class Index extends Page 
  2.    @Override 
  3.    public String getTemplate() 
  4.    { 
  5.       try 
  6.       { 
  7.           return FileUtils.readFileToString(new File(getSession().getServletContext().getRealPath("Index.html"))); 
  8.       } 
  9.       catch (IOException e) 
  10.       {          
  11.           throw new RuntimeException(e);         
  12.       }      
  13.    } 
  14.    
  15.    @Override 
  16.    public void onLoad() 
  17.    { 
  18.       Label lab = (Label)getRoot().findComponent("lab3"); 
  19.       lab.addComponent(new Literal("<a href=\"#\">hi i am dynamic!!</a>")); 
  20.       Integer count = (Integer)getViewSate().get("count"); 
  21.       if (null == count) 
  22.       { 
  23.           count = 0; 
  24.       } 
  25.       count ++; 
  26.       getViewSate().put("count", count); 
  27.       Button btn = new Button("Ok" + count);    
  28.       lab.addComponent(btn); 
  29.    }   

public class Index extends Page
{
   @Override
   public String getTemplate()
   {
      try
      {
          return FileUtils.readFileToString(new File(getSession().getServletContext().getRealPath("Index.html")));
      }
      catch (IOException e)
      {         
          throw new RuntimeException(e);        
      }     
   }
  
   @Override
   public void onLoad()
   {
      Label lab = (Label)getRoot().findComponent("lab3");
      lab.addComponent(new Literal("<a href=\"#\">hi i am dynamic!!</a>"));
      Integer count = (Integer)getViewSate().get("count");
      if (null == count)
      {
          count = 0;
      }
      count ++;
      getViewSate().put("count", count);
      Button btn = new Button("Ok" + count);   
      lab.addComponent(btn);
   }  
}



     Sopo则是由neko解析模板,生成页面的组件树,web.sopo.template这个包下面包含了所有的模板解析类。每个page都有一个根组件
ComponentRoot web.sopo.page.Page.getRoot(),当开始绘制的时候则会从跟组件开始绘制。它的特点是可以在程序逻辑阶段动态的改变组件树的构造,上面的例子可以看到动态的加了个链接和按钮。使用了它的viewstate特性—存贮页面级变量,这和asp.net很像。

比较

     这三种都支持模板(包括页面模板和组件模板),共同特点是模板是html格式,美工可以直接编辑模板,没有讨厌的jsp标签.wicket取经于 tapestry,tapestry取经于asp.net,而sopo也是学asp.net并且和它最像。Wicket需要后台add对应模板的组件,通过匹配,这样做虽然可以动态的决定绘制组件的类型但是也比较繁琐,它类似于swing的方式,但是Mode这个概念入侵很大,通过session来保持状态。tapestry通过模板和组件的绘制来展示页面,不允许你new 一个组件,并且和prototype, scriptaculous集成了,它的performance是这三个中最快的,虽然page和组件都是pojo,但是有注入依赖,到底这个特性有没有用那是见仁见智了。Sopo则是比较灵活,可以动态的修改组件树,和asp.net非常接近,写组件和tapestry一样非常清晰,概念和实现都很单,缺点是它的性能只适用于中小型应用。


Total views.

© 2013 - 2024. All rights reserved.

Powered by Hydejack v6.6.1