阅读更多

8顶
0踩

编程语言

原创新闻 比较Wicket 1.5和Tapestry 5

2008-09-16 15:17 by 副主编 QQbyte 评论(15) 有10666人浏览
Struts框架一度很流行,现在还有很多开发者使用Struts,因为处理遗留代码和投资方面的原因,有更多的开发者已经开始转向使用基于组件的框架。JSF是最受欢迎的组件框架之一,因为JSF是JCP的一部分,而且得到很多厂商支持。JSF 2.0即将发布,不过本文要讨论的是另外两个基于组件框架:Wicket 1.5和Tapestry 5。

很快,Apache基金会将会发布两个有趣的框架新的版本:Wicket 1.5和Tapestry 5。很多人会问,这两个哪个更好?下面我们将在同一平台上对它们做比较。

1。Build Tool

对于很多开发者来说,build tool不是特别重要,但是这是值得考虑的因素之一。Wicket 1.5和Tapestry 5都使用maven作为build tool,这个它们没有区别。

2。Configuration 配置

Wicket 1.5和Tapestry 5都是采用xml,必须要配置的文件是web.xml。其他的,还需要配置xml设置页面调用的action等。这两个框架都认为开发框架应该负责生成URL和页面渲染的顺序,而不是让开发者在xml配置告诉框架如何做。

Wicket的web.xml

<web-app>
    <display-name>wicket</display-name>
	<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <filter>
        <filter-name>wicket</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
<param-name>applicationClassName</param-name>
<param-value>agilist.lab.WicketApplication</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>wicket</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>


如上显示,大多数配置在Java class:WicketApplication中,WicketApplication是一个用来定义你的web应用的java class。

下面是WicketApplication的部分代码:

public class WicketApplication extends WebApplication{
	public WicketApplication(){}

    	public void init(){
        		super.init();
    	}

	public Class<HomePage> getHomePage() {
		return HomePage.class;
	}
}

WicketApplication扩展了WebApplication,后者用来通过HTTP协议调用页面。在getHomePage()中返回index.html

Tapestry 5

下面看看Tapestry 5的配置,和Wicket类似,唯一必须要配置的文件是web.xml。

<web-app>
    <display-name>tapestry5</display-name>
    <context-param>
<param-name>tapestry.app-package</param-name>
<param-value>agilist.lab</param-value>
    </context-param>
    <filter>
        <filter-name>app</filter-name>
        <filter-class>org.apache.tapestry5.TapestryFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>app</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>


在web.xml中,你告诉tapestry到哪里去找到你的页面,组件和mixins。在配置中,你的页面,组件和mixins应该在以下目录中:

    * Components: agilist.lab.components
    * Pages: agilist.lab.pages
    * Mixins: agilist.lab.mixins

tapestry 5也拥有配置java class的能力,也类似Wicket。

public class AppModule
{
    public static void bind(ServiceBinder binder)
    {
        binder.bind(Member.class);
    }

    public static void contributeApplicationDefaults(
            MappedConfiguration<String, String> configuration)
    {
        configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en");
        configuration.add(SymbolConstants.PRODUCTION_MODE, "false");
    }
}


这两个框架在配置方面做的都很棒。

3。Controller/Page Class

Wicket 和 Tapestry,都是被称为基于 controller in action的框架,两者都是同一的方式来匹配page和class。

Tapestry中,比如我有一个AddMemberPage.java,我的模板名字就是AddMemberPage.html,在Wicket中是用AddMemberPage.tml作为模板。

Wicket:

wicket page class:

public class AddMemberPage extends BasePage {
    private static final Logger logger = LoggerFactory.getLogger(AddMemberPage.class);

    private Member member;

    public AddMemberPage() {
        add(new AddMemberForm("addMemberForm", new CompoundPropertyModel( new Member() )));
    }

    public class AddMemberForm extends Form {
	public AddMemberForm(String id, final CompoundPropertyModel model) {
	    	super(id, model);

	    	member = (Member)model.getObject();

	        add(new TextField("name"));

	        add(new Button("save"){
			public void onSubmit(){
                    			logger.info("Member name: {}", member.getName());
	    	    	}
	        });
	 }
    }
}



这是作为父class的BasePage class:

public class BasePage extends WebPage{
    public BasePage() {
        add(new PageLink("homeLink", HomePage.class)
             .add(new Label("homeLabel", new ResourceModel("home"))));

        add(new BookmarkablePageLink("addMemberLink", AddMemberPage.class)
            .add( new Label("addMemberLabel", new ResourceModel( "member.add" ) ) )
        );
    }
}



Tapestry 5:

Tapestry 5 Page class:

public class Add {
    @Inject private Logger logger;

    @Inject @Property @Parameter private Member member;

    void onSelectedFromSave(){
        logger.info("Member name: {}", member.getName());
    }
}


和wicket相同。你必须定义layout class给模板使用。和wicket不同点在于 tapestry 5 模板中使用组件而不是继承。下面是layout class:

public class Layout {
}


因为layout将作为一个组件,所以必须处于组件包下面。

wicket page class比tapestry 5长很多,不过很有趣,你会发觉wicket中的page class类似swing controller,而tapestry 5和JSF方式更象。

4。模板

Wicket 1.5和Tapestry 5的模板都是使用普通HTML,你不需要调用任何特殊的taglib。

wicket:

wicket通过继承方式使用模板,有一个parent父page,作为主要和涉及所有layout的子片断的内容。

<html>
<head>
</head>
<body>
<div  id="wrap">
<div id="header">
            <a  href="#" wicket:id="homeLink"><span wicket:id="homeLabel" /></a>
            <a href="#" wicket:id="addMemberLink"><span wicket:id="addMemberLabel" /></a></div>
<div  id="content">
            <wicket:child /></div>
<div  id="footer">
            Copyright</div>
</div>
</body>
</html>


这和之前的BasePage html layout一致。使用wicket:child标签,就可以让其他子页面继承模板。

<html>
<head></head>
<body>
    <wicket:extend>
    <form wicket:id="addMemberForm">
<table>
<tr>
<td>Name</td>
<td><input type="text" wicket:id="name"/></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" wicket:id="save" /></td>
</tr>
</table>
</form>
    </wicket:extend>
</body>
</html>


Tapestry

Tapestry5 模板使用的是组件方式:

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
</head>
<body>
<div  id="wrap">
<div id="header">
            <a t:type="PageLink" page="home">${message:home}</a>
            <a t:type="PageLink" page="member/Add">${message:member.add}</a></div>
<div  id="content">
            <t:body /></div>
<div  id="footer">
            Copyright</div>
</div>
</body>
</html>


t:body用来定义什么地方来放置一个组件模板。

使用模板:

<t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<table>
    <t:form>
<tr>
<td>Name</td>
<td><input t:type="TextField" t:id="name" t:size="30" t:value="prop:member.name"/></td>
</tr>
<tr>
<td></td>
<td><input t:type="Submit" t:id="save" value="save" /></td>
</tr>
</t:form></table>
</t:layout>


5。Spring integration 和Spring 集成

Wicket and Tapestry中集成spring都很简单,无缝集成。

wicket:

在init()加一行代码:

addComponentInstantiationListener(new SpringComponentInjector(this));


类似这样:

public class WicketApplication extends WebApplication{
	public WicketApplication(){}

    	public void init(){
        		super.init();

		addComponentInstantiationListener(new SpringComponentInjector(this));
    	}

	public Class<HomePage> getHomePage() {
		return HomePage.class;
	}
}


接下来就可以使用spring bean从page class中使用annotating @SpringBean调用:

public class AddMemberPage extends BasePage {
    private static final Logger logger = LoggerFactory.getLogger(AddMemberPage.class);

    private Member member;

    private @SpringBean MemberService service;

    public AddMemberPage() {
        add(new AddMemberForm("addMemberForm", new CompoundPropertyModel( new Member() )));
    }

    public class AddMemberForm extends Form {
	public AddMemberForm(String id, final CompoundPropertyModel model) {
	    	super(id, model);

	    	member = (Member)model.getObject();

	        add(new TextField("name"));

	        add(new Button("save"){
		public void onSubmit(){
                    		logger.info("Member name: {}", member.getName());
                    		service.add(member);
	    	    }
	        });
	}
     }
}


Tapestry 5

在Tapestry 5中,spring bean被看作tapestry 5的组件,无缝调用和通过tapestry 5 IoC注入。为了集成spring,你需要修改web.xml中一行:

 <filter>
    <filter-name>app</filter-name>
    <filter-class>org.apache.tapestry5.spring.TapestrySpringFilter</filter-class>
  </filter>


接下来就能注入spring bean进入page class通过简单的@Inject annotation:

public class Add {
    @Inject private Logger logger;
    @Inject private MemberService service;

    @Inject @Property @Parameter private Member member;

    void onSelectedFromSave(){
        logger.info("Member name: {}", member.getName());
    }
}


6。Page unit testing

Wicket and Tapestry5的Page unit testing都不需要启动一个servlet容器。

wicket:

不需要锁定一个特殊测试框架,你可以使用JUnit或者TestNG都没问题,因为wicket提供helper class:

WicketTester来做page class的Unit testing:

public class TestHomePage extends TestCase
{
	private WicketTester tester;

	@Override
	public void setUp()
	{
		tester = new WicketTester(new WicketApplication());
	}

	public void testRenderMyPage()
	{
		//start and render the test page
		tester.startPage(HomePage.class);

		//assert rendered page class
		tester.assertRenderedPage(HomePage.class);
	}
}


Tapestry 5

也不需要锁定一个特殊测试框架:

public class MyTest extends Assert
{
    @Test
    public void test1()
    {
        String appPackage = "org.example.app";
        String appName = "LocaleApp";
        PageTester tester = new PageTester(appPackage, appName, "src/main/webapp");
        Document doc = tester.renderPage("MyPage");
        assertEquals(doc.getElementById("id1").getChildText(), "hello");
    }
}


以上就是对两个框架的基本比较,比较它们的相同点和不同点。你觉得哪个更好?我认为两者都很酷,只是看你喜欢哪种风格而已。

另外一个问题就是,这两个框架Wicket 和Tapestry 要不要合并?就像struts和webwork一样,因为都是在Apache旗下?你的意见?



8
0
评论 共 15 条 请登录后发表评论
15 楼 hpgood 2008-10-04 01:45
jsf1.2的不成熟,使我不得不转用T5.并跟住apache的最新发布版本升级`~期待T5 bete.希望T5相关的插件成熟起来~~T5的组件化思想比较彻底.jsf只是个标准.jsf+glassfish在未来两年后,可能会热起来. T5希望快些稳定下来,让更多人使用.
14 楼 kenken0y 2008-09-22 12:53
wicket 1.4都还没有发布就在比较wicket 1.5和tapestry5了
13 楼 lococode 2008-09-18 09:18
引用
Tapestry中,比如我有一个AddMemberPage.java,我的模板名字就是AddMemberPage.html,在Wicket中是用AddMemberPage.tml作为模板。

T5的最新版本中,模板也叫AddMemberPage.tml了~~
12 楼 Allen 2008-09-17 08:44
这个事情。就像是在足球世界里面比较 智利队 和 丹麦队 一样的效果吧。
11 楼 hantsy 2008-09-16 23:44
http://www.theserverside.com/news/thread.tss?thread_id=50634
10 楼 hantsy 2008-09-16 23:43
也太牛B了吧,wicket 1.5在哪里啊。。。
老外写的是处在开发中的wicket 1.4 与t5的比较。
9 楼 congpeixue 2008-09-16 19:41
click  framework 再给大家贡献一个 
8 楼 rwx7699 2008-09-16 18:38
tapestry比wicket更早流行,但是因为3,4,5不兼容,所以使用人员比较分散。目前tapestry5缺少一个有力的插件和文档、例子,前途还是光明的。
7 楼 jwsh1984 2008-09-16 17:45
支持力度和可用插件, 扩展性对比, wicket和tapestry是无法相比的, tapestry优先于wicket
6 楼 rockjava 2008-09-16 17:31
现在看来基于组件的框架“竞争”也很激烈啊。
用JSF做过几个项目,但和基于action框架相比,觉得还是不够灵活。
分别用Tapestry5和Wicket做了demo感觉要比JSF好些,但还是很期待
JSF2.0
5 楼 Ghostbb 2008-09-16 16:58
不知道作者想表达什么意思!费解中。。。
4 楼 hetylei 2008-09-16 16:52
急需IDE图形化设计支持
3 楼 hanting99 2008-09-16 16:32
Tapestry5 的性能很不错。不过要是升级在像4与5的差别那样大的话这个框架估计无法很好的推广。每次升级变化太大没几个程序员感用
2 楼 fight_bird 2008-09-16 16:20
本来很看好Wicket,但做了一个小的Demo后决定放弃在项目实践中使用,“锤子”是好的“锤子”,但也仅仅是个锤子。
1 楼 tapestry 2008-09-16 15:49
这么快就翻译过来了,支持下。

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • windows下C++多线程学习之一(多线程基础)

    作为一个C++程序员,相信大家对多线程都不陌生。最近自己在系统的学习多线程编程,发现了很多曾经没有注意到的东西,系统的整理了一下这些知识。方便自己以后查阅,也希望能够能够方便他人。 一、线程基础   1.      作业—> 进程—> 线程 作业:进程组的概念,将进程添加到一个作业中,能够通过作业内核对象来集中控制,设置一些额外的属性。 进程:一个正在运行的程序实例,由系统用

  • MFC中PeekMessage的使用,非阻塞消息循环

    在程序设计的时候经常要进行一个数据循环,比如播放音乐需要循环的向缓冲区里面写入数据,在这个时候比较通用的方法是建立一个线程做事情,但是有时候不想创建多线程就可以使用微软提供的PeekMessage方法,使用起来很简单,如下 while(waveOutUnprepareHeader((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR))!= MM...

  • C++ 多线程阻塞 (多线程同步)(MsgWaitForMultipleObjects)

    在主线程定要禁止使用waitforsingleobject(),原因是会阻塞主线程的消息循环,所以必须使用另一种 MsgWaitForMultipleObjects,即可以让消息通过,下面就是一个基于MsgWaitForMultipleObjects与Event,实现多线程同步这样。HANDLE g_Handle;//全局的句柄g_Handle=CreateEvent(NULL,FALSE,F

  • MFC MFC中L、_T()、_TEXT()、TEXT()区别

    MFC中L、_T()、_TEXT()、TEXT()区别 1、L L"xxx"表示字符串使用Unicode编码。 2、_T()、_TEXT()、TEXT() _T(“xxx”)、_TEXT("xxx")、TEXT("xxx")功能完全相同,兼容Unicode编码和ASCII编码。即如果项目使用Unicode字符集,那么将字符串"xxx"装换为L"xxx";如果项目使用ASCII字符集,那么“...

  • MFC多线程技术

    线程状态用类_AFX_THREAD_STATE描述,模块状态用类_AFX_MODULE_STATE描述,模块-线程状态用类_AFX_MODULE_THREAD_STATE描述。在线程执行查找文件任务的时候,如果找到的是目录就将它添加到列表中,若找到的是文件,就用自定义CheckFile函数进行比较,判断是否符合查找条件,若符合就打印出来,显示给用户。在MFC中,一般用全局函数AfxBeginThread()来创建并初始化一个线程的运行,该函数有两种重载形式,分别用于创建工作者线程和用户界面线程。

  • PeekMessage和GetMessage函数的主要区别

    PeekMessage和GetMessage函数的主要区别有: 1. GetMessage的主要功能是从消息队列中“取出”消息,消息被取出以后,就从消息队列中将其删除;而PeekMessage的主要功能是“窥视”消息,如果有消息,就返回true,否则返回false。也可以使用PeekMessage从消息队列中取出消息,这要用到它的一个参数(UINT wRemoveMsg),如果设置为PM_REM

  • 打乒乓程序的PeekMessage版本

    今天看到Programming  Windows多任务及多线程那章,提到了PeekMessage( )函数,那这个不是正好可以用在打乒乓程序中吗,就不用定时器了,应用PeekMessage( )函数的版本如下:#include #include "resource.h"LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;void D

  • MFC多线程

    目录概述一个简单示例分析参考资料 概述 多线程最适用于多核CPU,如果在单核CPU下运行多个都需要大量消耗CPU资源的线程,那么多个线程会由于抢占CPU而消耗大量资源。反而影响程序的运行。 每个进程由操作系统自动创建一个主线程。一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源。所以线程间的通讯非常方便。 线程函数必须是全局函数 一个简单示例 UINT...

  • 基于VC6.0的MFC应用程序开发中的一…

    ---------------------------------------代码每天都要敲,总结每次都要写------------------------------------距离上一次奋力写代码已过了一星期,期间经过了二级考试,感觉并无收获。并且我认为C++跟C的关系不是太大,C++很好的人C不一定很好。上一次做了一个数据库测试的软件,因为知识的匮乏,过程中出现各种bug,好在一步一步解决了...

  • mfc 多线程使用

    MFC的线程有两种,一种称为Work线程,一种称为UI线程。一般情况下Work线程与UI线程的区别主要在于UI线程有消息队列(并不是有没有界面,这点要注意,UI线程也是可以没有界面的)。 一、有关创建线程的三种方法: 1.C语言函数,调用_beginthread(); 2.API函数,调用CreateThread(); 该函数创建线程将返回一个线程句柄,通过该句柄你可以控制和操作该线程,线程结束后就关闭该句柄 3.MFC函数,调用AfxBeginThread(); 推荐使用MFC函数AfxBegi...

  • 基于线程的二维刀削程序

    执行车削 执行退刀 工程:mutiThread 程序:mutiThreadDlg.h   typedef struct property{ HWND hwnd; int speed; int X; int Y; int QuitX; int QuitY; CRect rect; }CuttingInfo ,*LPINFO; UINT toolMove(LPVOID lpparameter);

  • VC6.0上基于MFC的应用开发软件架构3

    ² MFC简介:MFC是一个应用程序框架,专门为微软的Windows操作系统创建应用程序而设计。MFC使用抽象、封装、继承、多态性和模块化的面相对象原则,在逻辑上将Windows API分类: 通用类、Windows API类、应用程序框架类以及高层抽象等。下面将这几个分类展开介绍: ü 通用类:提供类似字符串处理的类、集合类和异常类; ü Windows API类:封装了所有的Windows...

  • Visual C++线程同步技术剖析

    Visual C++线程同步技术剖析   使线程同步  在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。  如果不采取适当的措施,其他线程往往会在线程处理任务结束前就去访问处理结果,这就很有可能得到有关处理结果的错误了解。例如,多个线程同时

  • MFC 线程编程

    原文地址线程简介我们知道一般情况程序中的代码都是按顺序从头开始一行一行的执行以最后.中间不能出现同时执行的情况.比如一段代码调用两个函数FunOne();FunTwo(); 只要当函数FunOne中的代码执行完才返回来执行FunTwo.假如逻辑上是有先后顺序那还真只能这样按顺序执行下来.不过有假如FunOne与FunTwo没有逻辑先后顺序,是相互独立的.比如两个函数分别处理两不同的文件one.tex

  • PeekMessage完美解决MFC主界面无响应

    一般主界面无响应的解决方案是,对于计算量过大的方法,另开工作者线程,如下: MFC支持两种线程:用户界面线程和工作者线程。 (1)用户界面线程:通常用于处理用户输入,响应由用户产生的事件和消息。用户界面线程通常有窗口,有自己的消息循环。CWinApp是一个用户界面线程对象的例子,因为它是从CWinThread派生出来的,而且要处理用户产生的事件和消息。...

Global site tag (gtag.js) - Google Analytics