1. 概述

Wicket 是一个基于Java的服务器端Web组件框架,目标是通过引入桌面UI开发中熟知的模式,简化构建Web界面的过程。

使用Wicket,仅需Java代码和符合XHTML规范的HTML页面即可构建Web应用,无需JavaScript或XML配置文件。

它在请求响应周期上提供了一层封装,使开发者能够避免底层操作,专注于业务逻辑。

本文将通过构建HelloWorld Wicket应用来介绍基础知识,然后使用两个内置组件的完整示例,展示它们之间的通信。

2. 安装设置

要运行Wicket项目,请添加以下依赖:

<dependency>
    <groupId>org.apache.wicket</groupId>
    <artifactId>wicket-core</artifactId>
    <version>7.4.0</version>
</dependency>

请查看Maven中央仓库的最新Wicket版本,与这里使用的可能不一致。

现在我们准备好构建第一个Wicket应用了。

3. HelloWorld Wicket

首先,我们需要继承WebApplication类,这是应用的基本入口点,至少需要重写Class<? extends Page> getHomePage()方法。

Wicket会使用这个类作为应用的主要入口点。在方法内,只需返回一个名为HelloWorld的类的对象:

public class HelloWorldApplication extends WebApplication {
    @Override
    public Class<? extends Page> getHomePage() {
        return HelloWorld.class;
    }
}

Wicket倾向于约定优于配置。向应用添加新网页需要创建两个文件:一个Java文件和一个同名(但扩展名不同)的HTML文件,位于同一目录下。只有当需要改变默认行为时才需要额外配置。

在源代码包目录下,首先添加HelloWorld.java

public class HelloWorld extends WebPage {
    public HelloWorld() {
        add(new Label("hello", "Hello World!"));
    }
}

接着是HelloWorld.html

<html>
    <body>
        <span wicket:id="hello"></span>
    </body>
</html>

最后,在web.xml中添加过滤器定义:

<filter>
    <filter-name>wicket.examples</filter-name>
    <filter-class>
      org.apache.wicket.protocol.http.WicketFilter
    </filter-class>
    <init-param>
        <param-name>applicationClassName</param-name>
        <param-value>
          com.baeldung.wicket.examples.HelloWorldApplication
        </param-value>
    </init-param>
</filter>

就这样,我们刚刚编写了第一个Wicket Web应用。

通过构建war文件(在命令行中使用mvn package)并部署到Jetty或Tomcat等Servlet容器,即可运行项目。

在浏览器中访问http://localhost:8080/HelloWorld/,将看到一个空白页面,显示消息Hello World!

4. Wicket组件

Wicket的组件由Java类、HTML标记和模型三部分组成。模型是组件用于访问数据的外观层。

这种结构提供了良好的关注点分离,通过将组件与数据相关操作解耦,提高了代码重用性。

接下来的例子演示如何为组件添加Ajax行为。它包含一个页面,包含两个元素:一个下拉菜单和一个标签。当下拉选择更改时,仅标签(标签本身)将被更新。

HTML文件CafeSelector.html的主体将非常简单,只有两个元素:下拉菜单和标签:

<select wicket:id="cafes"></select>
<p>
    Address: <span wicket:id="address">address</span>
</p>

在Java侧,我们创建标签:

Label addressLabel = new Label("address", 
  new PropertyModel<String>(this.address, "address"));
addressLabel.setOutputMarkupId(true);

Label构造函数的第一个参数匹配HTML文件中分配的wicket:id,第二个参数是组件的模型,它是底层数据的包装器,用于在组件中显示数据。

setOutputMarkupId方法使组件成为Ajax修改的候选者。现在,我们创建下拉列表,并为其添加Ajax行为:

DropDownChoice<String> cafeDropdown 
  = new DropDownChoice<>(
    "cafes", 
    new PropertyModel<String>(this, "selectedCafe"), 
    cafeNames);
cafeDropdown.add(new AjaxFormComponentUpdatingBehavior("onchange") {
    @Override
    protected void onUpdate(AjaxRequestTarget target) {
        String name = (String) cafeDropdown.getDefaultModel().getObject();
        address.setAddress(cafeNamesAndAddresses.get(name).getAddress());
        target.add(addressLabel);
    }
});

创建方式类似于标签,构造函数接受wicket:id、模型以及咖啡馆名称列表。

然后添加AjaxFormComponentUpdatingBehavior,并在onUpdate回调方法中,一旦发起Ajax请求,就更新标签的模型。最后,将标签组件设置为刷新目标。

为了改变标签显示的内容,我们只需修改一个POJO。修改Java对象如何转化为网页上的变化,这一机制由Wicket在幕后处理,对开发者来说并不重要。

Wicket提供了丰富的预置Ajax组件。组件目录及其实时示例可在这里找到。

5. 总结

在这篇入门文章中,我们介绍了基于组件的Java Web框架Wicket的基础知识。

Wicket提供了一层抽象,旨在完全消除底层代码的繁琐工作。

我们包括了两个简单的示例,您可以在GitHub上找到它们,以了解使用此框架进行开发的样子。