作者:David R. Heffelfinger 原文:http://ensode.net/wicket_first_look.html
译者:Jason Ho
介绍
当 Kevin Taylor 询问他的个人博客的那些读者们正在用什么web 框架时,他们中的大多数告诉他他们正在使用Wicket。这种情况多少归由于目前的市场,然而我还是很好奇,所以下载了Wicket的beta最新版一睹它的魅力。
Wicket的出色之处在于,它用标准的HTML页面作为它的前端(front end),从而使得HTML设计人员在设计页面时完全自由和独立,他们可以自由选择使用Dreamweaver、FrontPage、NVU(New view)获其他所见即所得(WYSIWYG)的工具来创建标记(markup)。Wicket的另一个特点是,开发Wicket web 应用不需要在诸如Struts或JSF那些框架中见到的xml配置文件。
我在写此文章之前对于Wicket并无经验,因此此文纯属一个Wicket新手的观点,希望它既是对Wicket的一个回顾,也是一份指南。
用Wicket写web应用
此前对于Wicket毫无经验,我想找一些在线教程和相关介绍,但并不是很多。
尽管wicket 的网站上有一些可供下载的例子,并且上面有JavaDoc,但这并不足以让我们了解这个框架是如何工作的。如果我能找到好的关于wicket的文档,我想我不会花那么长时间才弄清楚我需要做什么。
我要做的第一件事情是尝试通过wicket显示一张不含动态域的简单HTML页面。在部署wicket应用时,在一个标准的部署描述符web.xml文件中声明该应用,用wicket.protocol.http.WicketServlet作为servlet,并且传递一个继承自类wicket.protocol.http.WebApplication的类的实例作为唯一的初始化参数,作为一个例子,下面是这个应用的web.xml文件的相关部分:
|
例子应用中继承自wicket.protocol.http.WebApplication的类并太大的实际意义,它所作的仅仅是在构造方法中调用getPages().setHomePage(WicketTestPage.class)而已,该方法调用将与WicketTestPage.java对应的HTML page设置为应用的初始页面。
一旦应用wicket应用被部署,就像任何标准的war文件被部署以后一样,我们就可以访问它了。现假设你的war文件的名字为wicketapp.war,并且使用如上述web.xml文件中的url pattern,我们就可以通过这个URL:http://localhost:8080/wickettestapp/app 来访问这个应用了。该URL假设你把应用部署在本地工作站上,而且servlet容器监听8080端口,我们也可以使用合适的主机名和端口。
Wicket 使用标准的HTML,所以我用一个模板创建了一个简单的页面,我在网站上的所有页面都相同地使用了这个模板。在下面的一个wicket实例中,创建了一个继承自wicket.markup.html.WebPage的类,并且没有为它添加任何组件,创建的HTML页面和类的文件名相同(不包括扩展名),然后打一个war包部署到Tomcat下测试。页面能够运行,而似乎HTML页面并没有找到被我部署在和HTML页面同目录下的css 样式表。在查看了Wicket官方发布的例子之后,我发现css文件需要部署在war文件的根目录下,而不是把它部署到HTML页面所在的目录下,而HTM页面所在的目录必须和相应的继承自WebPage的class文件所属的目录相同,花了好一会儿这才让我弄清楚怎么让HTML页面能够看到css。在越过了这个“栅栏”后,我下一步要做的就是创建一个含form表单的页面,用户输入某些值、提交表单,然后给出一个一个显示刚才输入的信息的确认页面。我选择了创建一个假想的在线pizza订购程序,通过一个下拉筐让用户选择pizza的外皮,选择框选择piazz上浇上的食物,还有一个备注文本框。
由于我几乎找不到在线的Wicket文档,我不清楚这个框架到底是如何工作的,我将做一些简要的说明以为后来的wicket框架用户节省些时间。Wicket有一个模型对象(Model Objects)的概念,这些对象都是简单的POJO(Plain Old Java Objects),它们具有页面上组件的值,这些模型对象在概念上与JSF中Backing Beans或Struts中Form Beans有些相似。HTML页面包含了一些Wicket组件,它们具有某些特殊HTML属性来使自身和哪些模型对象映射,属性的名字和学和模型对象的域成员对应,当用户在表单中输入数据并提交后,模型对象的一些相应的属性会会被用户输入的数据所填充。
在用wicket写应用程序时,每一个HTML页面必须要有一个对应的继承自WebPage类的Java对象,HTML文件和Java类的名字必须相同。例如,名为“MyWicketPage.html”的HTML文件必须有一个与之对应的“MyWicketPage.java”文件,HTML文件必须部署在与之对应的java类文件所在的目录下。Wicket 有一些与HTML表单域映射的组件,这些组件能够被部分添加到彼此的上面,就像HTML页面的DOM,如果页面含有一个下拉框、若干个选择框和一个文本框,那么在一个Form类的实例中就必须添加下拉选择框、选择框和文本框这些类的实例。而后,我们需要把这个Form添加到HTML页面对应的java类中去。对于这个测试的应用程序,相关的html代码如下:
<form wicket:id="pizzaForm"> <table style="text-align: left; width: 427px; height: 112px;" border="1" cellpadding="0" cellspacing="0"> <tbody> <tr> <td style="font-weight: bold; text-align: right;">Crust:</td> <td><select wicket:id="crust"> <option>option 1</option> <option>option 2</option> <option>option 3</option> </select></td> </tr> <tr> <td style="font-weight: bold; text-align: right;">Toppings:</td> <td>Pepperoni<input wicket:id="pepperoni" type="checkbox" /> Sausage<input wicket:id="sausage" type="checkbox" /> Onions<input wicket:id="onions" type="checkbox" /> Green Peppers<input wicket:id="greenPeppers" type="checkbox" /></td> </tr> <tr> <td style="font-weight: bold; text-align: right;">Comments:</td> <td><input maxlength="50" size="50" wicket:id="comments" type="text" /></td> </tr> <tr> <td style="text-align: center;" colspan="2"><input value="Submit" name="Submit" type="submit" /></td> </tr> </tbody> </table> </form> |
相应的继承自wicket.markup.html.WebPage 的类的java代码(不含import和package名):
public class WicketTestPage extends WebPage { PizzaForm pizzaForm = new PizzaForm("pizzaForm"); public WicketTestPage() { super(); add(pizzaForm); } } |
必须继承wicket.markup.html.form.Form 类,因为它提供了一个在表单被提交时执行的onSubmit()方法。我写了一个PizzaForm类来与html页面中的form映射,PizzForm类相关源代码片段如下:
|
基本上,这里我所做的是把所有必须的Wicket组件添加到form中去。如果你对Wicket不是很熟悉,下拉框组件部分的代码可能一时间有点难明白,别担心,后面将为你解释。
最后,我写了一个PizzaModel类来保存用户在表单上输入的数据:
|
注意看PizzaModel类的成员的名字是如何同HTML文件中的<wicket:id>属性对应的。
我要将PizzaModel类中的属性与HTML表单域绑定起来,所需要做的只是在PizzForm类中添加下面一行代码:
setModel(new CompoundProtertyModel(pizzaModel));
wicket.model.CompoundPropertyModel
类负责将模型对象(本例中是PizzaModel)中的成员封装上相适应的用户输入值。
从Wicket官方的例子中,如何将模型对象中的成员同html文件中的下拉框组件映射起来,这一点并不是很清楚,下面是我让它运行起来的做法:
我写了一个新的模型(Model)类来模拟下拉框中的选项,对于这个测试应用程序,我写了一个新的名为CrustType的类:
|
接下来,我要实例化wicket.markup.html.form.DropDownChoice 类,它是一个用来与html的<select>域(通常称作“下拉框”)映射的Wicket组件,使用下面的构造器:
public DropDownChoice(java.lang.String id,
IModel model,
IModel choices,
IChoiceRenderer renderer)
为了使它们一起运行起来,我要传递的参数如下:
crustDropDown = new DropDownChoice(
"crust",new PropertyModel(pizzaModel, "crust"), Arrays
.asList(new CrustType[]
{ new CrustType("Thin & Crispy"),
new CrustType("Hand Tossed"),
new CrustType("Pan Pizza") }),
new ChoiceRenderer("text", "id"));
pizzaModel是同HTML表单对应的模型对象类的一个实例,“crust” 是这个模型中的一个属性的名字,它将保存用户在下拉框中所选择的项的值。wicket.markup.html.form.ChoiceRenderer
实现 wicket.markup.html.form.IChoiceRenderer
接口,ChoiceRenderer
构造器的两个参数分别表示要显示的文本的内容和下拉框选择项的值。
在我弄清楚如何封装PizzaModel的crust属性后,最后一步只是显示一个确认页面用来现实用户的所有输入。
为了能够处理用户输入的值,我们必须覆写wicket.markup.html.form.Form
的 onSubmit()方法。PizzaForm类的onSubmit方法如下:
|
这里我们关心的是getModelObject()和requestCycle.setResponsePage()两个方法。getModelObject()方法调用得到一个已经封装好用户输入值的模型对象的实例;requestCycle.setResponsePage()将浏览器定向到一个新的页面,浏览器将被定向到的WebPage那个实例必须含有一个用模型对象实例作为参数的构造器。
下面即是确认页面的源代码:
public WicketTestConfPage(PizzaModel pizzaModel)
|
它所作的一切就是创建一些标签来现实模型对象的值,并且它用这个模型对象作为它唯一构造器的参数。
这里是相应的HTML文件的相关片段:
|
这里我们关心的是那些<span>域,它们与WicketTestConfPage.java
类中的那些label相对应。你可能已注意到一些<span>标签里面本身有文本,它只会在浏览器模拟(mock up)页面时才会显示,当它在Wicket应用程序中显示时,它们将显示任何与之对应的Label实例所含有的值。
在随便输入一些数据并提交表单后,这里我们就看到了确认页面的样子:
小结:
Wicket具有胜于其它web应用框架的优点:
l 它使得(原来)关心的东西能够简洁地分离开来,这使得web设计人员不必向HTML文件中添加任何特殊的标记来使页面同wicket一起运作,允许他们使用任何所见即所得的编辑工具来创建页面。
l 它使得我们很容易创建能够在一个servlet容器或应用程序服务器外不执行的Java代码。基于这些原因,在创建web应用程序和动态web站点时,Wicket是一个好的选择。
l 它不需要特别的XML配置文件。
Wicket的缺点:
l 它一点也不像诸如Struts和JavaServer Faces等其它web应用程序框架那样文档化。
l 它对于AJAX的支持还很有限(在最新的beta版本中),尽管更多的AJAX支持已被列入计划之中。
感谢
感谢Gregg Bolinger,、Johan Compagner 和 Eelco Hillenius给予了宝贵的反馈意见。
资源
l Kevin Taylor的报告说,他的大多数读者推荐Wicket
l JavaLobby关于Kevin Taylor的调查结果的讨论
后记
目前自己正在学习wicket,所以顺便翻译了此文。这也是我第一次翻译英文文档,英文不是很好,翻译自己感觉有些生硬,还望路过此地的朋友和有经验的前辈,对译文给些意见,加以斧正,本人不胜感激!