wicket,tapestry5,sopo 模板实现比较

1 Wicket实现

Wicket模板是html格式,示例:index.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 中手动添加进组件列表中。

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.Markup的List<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 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

{

@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格式就可以,示例:

<!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有些像,因为模板里面指明了组件类型,所以就不需要再添加了.

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