July 23, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Wicket: The First Steps

  • April 23, 2007
  • By Karthik Gurumurthy
  • Send Email »
  • More Articles »

In this article, after a quick introduction to Wicket, you will learn to obtain and set up the requisite software for Wicket-based web development. Then you will learn to develop interactive web pages using Wicket. Along the way, you will be introduced to some key Wicket concepts.

What Is Wicket?

Wicket is a component-oriented Java web application framework. It's very different from action-/request-based frameworks like Struts, WebWork, or Spring MVC where form submission ultimately translates to a single action. In Wicket, a user action typically triggers an event on one of the form components, which in turn responds to the event through strongly typed event listeners. Some of the other frameworks that fall in this category are Tapestry, JSF, and ASP.NET. Essentially, frameworks like Struts gave birth to a concept of web-MVC that comprises coarse-grained actions-in contrast to the fine-grained actions we developers are so used to when programming desktop applications. Component-oriented frameworks such as Wicket bring this more familiar programming experience to the Web.

Obtaining and Setting Up Wicket

Wicket relies on the Java servlet specification and accordingly requires a servlet container that implements the specification (servlet specification 2.3 and above) in order to run Wicket-based web applications. Jetty (http://jetty.mortbay.org) is a popular, open-source implementation of the servlet specification and is a good fit for developing Wicket applications.

The Wicket core classes have minimal dependencies on external libraries. But downloading the jar files and setting up a development environment on your own does require some time. In order to get you quickly started, Wicket provides for a "Quick Start" project. The details can be found here: http://wicket.sourceforge.net/wicket-quickstart/. Download the latest project files through the "Download" link provided on the page. Having obtained the project file, extract it to a folder on the file system. Rename the folder to which you extracted the distribution to your required project name. As you can see in Figure 1, I've renamed the directory on my system to Beginning Wicket.

Figure 1. Extract the contents of the Wicket Quick Start distribution to a file system folder.

Setting up Wicket Quick Start to work with an IDE like Eclipse is quite straightforward. It is assumed that you have Eclipse (3.0 and above) and Java (1.4 and above) installed on your machine.

Eclipse Development Environment Setup Using Quick Start

The steps for setting up Eclipse with Wicket Quick Start are as follows:

  1. Copy the files eclipse-classpath.xml and .project over to the project folder that you just created. These files are available in the directory src\main\resources under your project folder.
  2. Create an Eclipse Java project, specifying you want it created from an existing source with the directory pointing to the one that you created earlier (the Beginning Wicket folder in this example, as shown in Figure 2). Accept the default values for other options and click Finish. This is all you require to start working with Wicket.

Figure 2. An Eclipse Java project pointing to the folder previously created.

Running the Application

The Quick Start application ships with an embedded Jetty server. You can start the server by right-clicking the src/main/java directory in the project and selecting the menu commands Run as Java application. If Eclipse prompts you for a main class, browse to the class named Start. This is all that is needed to kick-start Wicket development.

You can access your first Wicket application by pointing the browser to http://localhost:8081/quickstart.

How to Alter the Jetty Configuration

The Jetty configuration file is located in the project directory src/main/resources/jetty-config.xml.

Notice from the file that Jetty, by default, is configured to start on port 8081. If you want to override the default Jetty settings, this is the file you need to be editing. Next, you will change the default web application context from quickstart to wicket, as demonstrated in Listing 1. You will also change the default port from 8081 to 8080.

Listing 1. The Modified jetty-config.xml

    <!--rest snipped for clarity -->

  <Call name="addListener">
    <Arg>
      <New class="org.mortbay.http.SocketListener">
          <Set name="Port"><SystemProperty name="jetty.port" default="8081"/></Set>
      <!--rest snipped for clarity -->
  <Call name="addWebApplication">
    <Arg>/wicket</Arg>
    <Arg>src/webapp</Arg>
  </Call>

After making the modifications in Listing 1, restart Jetty. Now the application should be accessible through the URL http://localhost:8080/wicket.

For more information on Jetty configuration files, refer to the document available at http://jetty.mortbay.org/jetty/tut/XmlConfiguration.html.

The web.xml for Wicket Web Development

You will find the src/webapp/WEB-INF folder already has a fully functioning web.xml entry. But that corresponds to the default Quick Start application. Since for the purposes of this walkthrough you will develop a Wicket application from scratch, replace the existing web.xml content with the one shown in Listing 2. This registers the Wicket servlet and maps it to the /helloworld URL pattern.

Listing 2. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD
Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <display-name>Wicket Shop</display-name>
    <servlet>
      <servlet-name>HelloWorldApplication</servlet-name>
      <servlet-class>wicket.protocol.http.WicketServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloWorldApplication</servlet-name>
        <url-pattern>/helloworld/*</url-pattern>
    </servlet-mapping>

</web-app>

The URL to access the application would be http://localhost:8080/wicket/helloworld.

Now that you are done with initial configuration, you'll develop a simple application that emulates a basic login use case.

Developing a Simple Sign-in Application

The sign-in application requires a login page that allows you to enter your credentials and then log in. Listing 3 represents the template file for one such page.

Listing 3. Login.html

<html>
  <title>Hello World</title>
  <body>
    <form wicket:id="loginForm">
           User Name <input type="text" wicket:id="userId"/><br/>
           Password <input type="password" wicket:id="password"/><br/><hr>
           <input type="submit" value="Login"/>
    </form>
  </body>
</html>

Figure 3 shows how this looks in the browser.

Figure 3. Login page when previewed on the browser

Double-click the file, and it will open in your favorite browser. Depending upon where you come from (JSP-based frameworks/Tapestry), it could come as a surprise to be able to open your template in a browser and see it render just fine. It must have been a dream sometime back with JSP-based frameworks, but luckily, it's a reality with Wicket. You would be forced to start a web server at minimum when using a JSP-based framework/JSF for that matter. Note that the template has a few instances of a Wicket-specific attribute named wicket:id interspersed here and there (ignored by the browser), but otherwise it is plain vanilla HTML.

Wicket mandates that every HTML template be backed by a corresponding Page class of the same name. This tells you that you need to have Login.java. This is often referred to as a

page-centric approach to web development. Tapestry falls under the same category as well.

The HTML template needs to be in the same package as the corresponding Page class. An internal Wicket component that is entrusted with the job of locating the HTML markup corresponding to a Page looks for the markup in the same place as the Page class. Wicket allows you to easily customize this default behavior though. All user pages typically extend Wicket's WebPage-a subclass of Wicket's Page class. There needs to be a one-to-one correspondence between the HTML elements with a wicket:id attribute and the Page components. The HTML template could in fact be termed as a view with the actual component hierarchy being described in the Page class. Wicket components need to be supplied with an id parameter and an IModel implementation during construction (some exceptions will be discussed in the section "How to Specify a CompoundPropertyModel for a Page." The component's id value must match the wicket:id attribute value of the template's corresponding HTML element. Essentially, if the template contains an HTML text element with a wicket:id value of name, then the corresponding wicket's TextField instance with an id of name needs to be added to the Page class. Wicket supplies components that correspond to basic HTML elements concerned with user interaction. Examples of such elements are HTML input fields of type text, HTML select, HTML link, etc. The corresponding Wicket components would be TextField, DropDownChoice, and Link, respectively.

Wicket Models

Components are closely tied to another important Wicket concept called models. In Wicket, a model (an object implementing the IModel interface) acts as the source of data for a component. It needs to be specified when constructing the component (doing a new); some exceptions will be discussed in the section "How to Specify a CompoundPropertyModel for a Page" later. Actually, IModel is a bit of a misnomer: it helps to think about Wicket's IModel hierarchy as model locators. These classes exist to help the components locate your actual model object; i.e., they act as another level of indirection between Wicket components and the "actual" model object. This indirection is of great help when the actual object is not available at the time of component construction and instead needs to be retrieved from somewhere else at runtime. Wicket extracts the value from the model while rendering the corresponding component and sets its value when the containing HTML form is submitted. This is the essence of the Wicket way of doing things. You need to inform a Wicket component of the object it is to read and update.

Wicket could also be classified as an event-driven framework. Wicket HTML components register themselves as listeners (defined through several Wicket listener interfaces) for requests originating from the client browser. For example, Wicket's Form component registers itself as an IFormSubmitListener, while a DropDownChoice implements the IonChangeListener interface. When a client activity results in some kind of request on a component, Wicket calls the corresponding listener method. For example, on an HTML page submit, a Form component's onSubmit() method gets called, while a change in a drop-down selection results in a call to DropDownChoice.onSelectionChanged. (Actually, whether a change in a drop-down selection should result in a server-side event or not is configurable.)

If you want to do something meaningful during Form submit, then you need to override that onSubmit() method in your class. On the click of the Login button, the code in Listing 4 prints the user name and the password that was entered.

Listing 4. Login.java

package com.apress.wicketbook.forms;

import wicket.markup.html.WebPage;
import wicket.markup.html.form.Form;
import wicket.markup.html.form.PasswordTextField;
import wicket.markup.html.form.TextField;

public class Login extends WebPage {

  /**
  * Login page constituents are the same as Login.html except that
  * it is made up of equivalent Wicket components
  */

  private TextField userIdField;
  private PasswordTextField passField;
  private Form form;

  public Login(){

    /**
    * The first parameter to all Wicket component constructors is
    * the same as the ID that is used in the template
    */

    userIdField = new TextField("userId", new Model(""));
    passField = new PasswordTextField("password",new Model(""));

    /* Make sure that password field shows up during page re-render **/

    passField.setResetPassword(false);

    form = new LoginForm("loginForm");
    form.add(userIdField);
    form.add(passField);
    add(form);
  }

// Define your LoginForm and override onSubmit
class LoginForm extends Form {
  public LoginForm(String id) {
    super(id);
  }
  @Override
  public void onSubmit() {
    String userId = Login.this.getUserId();
    String password = Login.this.getPassword();
    System.out.println("You entered User id "+ userId +
               " and Password " + password);
  }
}

/** Helper methods to retrieve the userId and the password **/

protected String getUserId() {
  return userIdField.getModelObjectAsString();
}

protected String getPassword() {
    return passField.getModelObjectAsString();
  }
}




Page 1 of 6



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel