Click is an open source project, licensed using the Apache license.
Click uses the event based programming model for processing Servlet requests and Velocity for rendering the response.
This framework uses a single servlet, called ClickServlet, to act as a request dispatcher. When a request arrives ClickServlet creates a Page object to processes the request and then uses the page's Velocity template to render the results.
Page provide a simple thread safe programming environment, with a new page instance is created for each servlet request.
Possibly the best way to see how Click works is to dive right in and look at some examples.
package examples.page; import java.util.Date; import net.sf.click.Page; public HelloWorld extends Page { public Date time = new Date(); }Next we would have a page template hello-world.htm:
<html>
<body>
<h2>Hello World</h2>
Hello world from Click at $time
</body>
</html>
And finally we have a click.xml configuration file which tells our Click
application to map hello-world.htm
requests to our HelloWorld page class.
<click-app>
<pages package="examples.page"/>
</click-app>
At runtime the ClickSerlvet maps a GET hello-world.htm
request to our page class example.page.HelloWorld and creates a new instance.
The HelloWorld page creates a new public Date object, which is automatically
added to the pages model using the fields name time.
The page model is then merged with the template which substitutes the
$time parameter with the Date object.
Velocity then renders the merged template which looks something like
Hello WorldHello world from Click at Wed May 28 15:52:29 EST 2005 |
public class CustomerPage extends Page { public Table table = new Table(); public ActionLink deleteLink = new ActionLink("deleteLink", "Delete", this, "onDeleteClick"); public CustomersPage() { table.setClass("its"); table.setPageSize(5); table.setShowBanner(true); table.setSortable(true); table.addColumn(new Column("id")); table.addColumn(new Column("name")); Column column = new Column("email"); column.setAutolink(true); table.addColumn(column); table.addColumn(new Column("category")); column = new Column("Action"); column.setDecorator(new LinkDecorator(table, deleteLink, "id")); column.setSortable(false); table.addColumn(column); } public boolean onDeleteClick() { Long id = deleteLink.getValueLong(); getCustomerService().deleteCustomer(id); return true; } /** * @see Page#onRender() */ public void onRender() { List list = getCustomerService().getCustomersByName(); table.setRowList(list); } }In this Page code example a Table control is declared and a number of Column objects are added. A deleteLink ActionLink control is used a decorator for the "Action" column. This control will invoke the Page onDeleteClick() method when it is clicked. Finally we have the Page onRender() method which is used to populate the Table control with rows before it is rendered. In our Page template we simply reference the $table object which is rendered when its toString() method is called.
<html>
<body>
<h3>Customers</h3>
$table
</body>
</html>
At runtime the Table would be rendered in the page as:
Customers
|
public class LoginPage extends Page { public Form form = new Form(); public LoginPage() { form.add(new TextField("username", true)); form.add(new PasswordField("password", true)); form.add(new Submit("ok", " OK ", this, "onOkClicked")); form.add(new PageSubmit("cancel", HomePage.class)); } public boolean onOkClicked() { if (form.isValid()) { User user = new User(); form.copyTo(user); if (getUserService().isAuthenticatedUser(user)) { getContext().setSessionAttribute("user", user); setRedirect(SecurePage.class); return false; } else { form.setError(getMessage("authentication-error")); } } return true; } }Note in this example the page's public form field is automatically added to its list of controls. Next we have the LoginPage template login.htm. The Click application automatically associates the login.htm template with the LoginPage class.
<html>
<body>
<h3>Login</h3>
$form
</body>
</html>
When the Login page is first requested the $form object will
automatically render itself as:
Login
|
Login
|