跳轉到內容

使用 Click 框架進行 Java Web 應用程式開發/簡介

來自華夏公益教科書,開放的世界,開放的書籍

Click 是一個適用於商業 Java 開發人員的簡單 JEE Web 應用程式框架。youtube Click 是一個開源專案,使用 Apache 許可證授權。

Click 使用基於事件的程式設計模型來處理 Servlet 請求,並使用 Velocity 來渲染響應。

該框架使用一個名為ClickServlet的單個 Servlet 充當請求排程器。當請求到達時ClickServlet建立一個Page物件來處理請求,然後使用頁面的 Velocity 模板來渲染結果。

頁面提供了一個簡單的執行緒安全程式設計環境,每個 Servlet 請求都會建立一個新的頁面例項。

可能是瞭解 Click 工作原理的最佳方法是直接深入研究一些示例

Hello World 示例

[編輯 | 編輯原始碼]

Click 中的 Hello World 示例看起來像這樣。

首先,我們將有一個HelloWorld頁面類

package examples.page;
 
import java.util.Date;
import net.sf.click.Page;

public HelloWorld extends Page 
{
    public Date time = new Date();
}

接下來我們將有一個頁面模板hello-world.htm:

<html>
  <body>
    <h2>Hello World</h2>
    Hello world from Click at $time
  </body>
</html>

最後,我們有一個click.xml配置檔案,它告訴我們的 Click 應用程式將hello-world.htm請求對映到我們的HelloWorld頁面類。

<click-app>
  <pages package="examples.page"/>
</click-app>

在執行時,ClickSerlvet 將 GET hello-world.htm 請求對映到我們的頁面類example.page.HelloWorld並建立一個新例項。HelloWorld 頁面建立一個新的公共Date物件,該物件使用欄位名稱自動新增到頁面的模型中time.

然後將頁面模型與模板合併,該模板將$time引數替換為Date物件。然後 Velocity 渲染合併後的模板,該模板看起來像

package examples.page;
 
import java.util.Date;
import net.sf.click.Page;

public HelloWorld extends Page 
{
    public Date time = new Date();
}

控制元件偵聽器示例

[編輯 | 編輯原始碼]

Click 包含一個庫(控制元件),它提供使用者介面功能。

最常用的控制元件之一是 ActionLink,您可以使用它讓 HTML 連結呼叫頁面物件上的方法。例如

public class ControlListenerPage extends Page 
{
   public ActionLink myLink = new ActionLink();
   public String msg;

   // ----------------------------------------------------------- Constructors

   /**
    * Create a new Page instance.
    */
   public ControlListenerPage() 
   {
       myLink.setListener(this, "onMyLinkClick");
   }

   // --------------------------------------------------------- Event Handlers

   /**
    * Handle the myLink control click event.
    */
   public boolean onMyLinkClick() 
   {
       msg = "ControlListenerPage#"   hashCode()
             " object method <tt>onMyLinkClick()</tt> invoked.";
 
        return true;
   }
}

在頁面類中,我們建立一個名為myLink的 ActionLink,並將控制元件的偵聽器定義為頁面方法onMyLinkClick()。當用戶點選 myLink 控制元件時,它將呼叫偵聽器方法onMyLinkClick().

在 Click 中,控制元件偵聽器方法可以具有任何名稱,但必須返回一個布林值。布林返回值指定是否應繼續處理頁面事件。這種控制元件偵聽器模式提供了一種簡便的方法來連線操作偵聽器方法,而無需定義匿名內部類。

回到我們的示例,在頁面模板中,我們定義了一個 HTML 連結,並讓myLink控制元件渲染連結的 href 屬性

<html>
  <head>
    <link type="text/css" rel="stylesheet" href="style.css"></link>
  </head>
  <body>

  Click myLink control <a href="$myLink.href">here</a>.

  #if ($msg)
    <div id="msgDiv"> $msg </div>
  #end

  </body>
</html>

在執行時,此頁面將渲染為

點選 myLink 控制元件 這裡

當用戶點選連結時,onMyLinkClick()方法被呼叫。然後該方法建立msg模型值,它在頁面中渲染為

點選 myLink 控制元件 這裡
ControlListenerPage#12767107 物件方法onMyLinkClick()被呼叫。

簡單 Table 示例

[編輯 | 編輯原始碼]

Click 中最實用的控制元件之一是Table控制元件。

下面提供了一個在客戶的Table中使用Page控制元件的示例用法

public class SimpleTablePage extends Page 
{
    public Table table = new Table();

    // ------------------------------------------------------------ Constructor

    public SimpleTablePage() 
    {
        table.setClass(Table.CLASS_ITS);

        table.addColumn(new Column("id"));
        table.addColumn(new Column("name"));
        table.addColumn(new Column("email"));
        table.addColumn(new Column("investments"));
    }

    // --------------------------------------------------------- Event Handlers

    /**
     * @see Page#onRender()
     */
    public void onRender() 
    {
    	List list = getCustomerService().getCustomersSortedByName(10);
    	table.setRowList(list);
    }
}

在此頁面程式碼示例中,聲明瞭一個 Table 控制元件,我們設定了表的 HTML 類,然後定義了表的數量Column物件。在列定義中,我們在建構函式中指定了列的名稱,該名稱用於表列標題,以及指定要渲染的行物件屬性。

我們需要做的最後一件事是用資料填充表格。為此,我們覆蓋了 PageonRender()方法並在渲染前設定表格行列表。

在我們的頁面模板中,我們只需引用$table物件,該物件在呼叫其toString()方法時被渲染。

<html>
<head>
$cssImports
</head>
<body>

$table

</body>
</html>
$jsImports

請注意,我們在上面還指定了 $cssImports 引用,以便表格可以在標題中包含任何 CSS 匯入或樣式,以及 $jsImports 引用,以便在底部包含任何 JavaScript 匯入或指令碼。

在執行時,Table 將在頁面中渲染為

高階 Table 示例

[編輯 | 編輯原始碼]

Table 控制元件還提供對

  • 自動渲染
  • 列格式化和自定義渲染
  • 自動分頁
  • 連結控制元件支援

下面提供了一個更高階的 Table 示例

public class CustomerPage extends Page 
{
    public Table table = new Table();
    public PageLink editLink = new PageLink("Edit", EditCustomer.class);
    public ActionLink deleteLink = new ActionLink("Delete", this, "onDeleteClick");

    // ------------------------------------- Constructor

    public CustomersPage() 
    {
        table.setClass(Table.CLASS_ITS);
        table.setPageSize(10);
        table.setShowBanner(true);
        table.setSortable(true);

        table.addColumn(new Column("id"));

        table.addColumn(new Column("name"));

        Column column = new Column("email");
        column.setAutolink(true);
        column.setTitleProperty("name");
        table.addColumn(column);

        table.addColumn(new Column("investments"));

        editLink.setImageSrc("/images/window-edit.png");
        editLink.setTitle("Edit customer details");
        editLink.setParameter("referrer", "/introduction/advanced-table.htm");

        deleteLink.setImageSrc("/images/window-delete.png");
        deleteLink.setTitle("Delete customer record");
        deleteLink.setAttribute("onclick", "return window.confirm('Are you sure you want to delete this record?');");

        column = new Column("Action");
        column.setTextAlign("center");
        AbstractLink[] links = new AbstractLink[] { editLink, deleteLink };
        column.setDecorator(new LinkDecorator(table, links, "id"));
        column.setSortable(false);
        table.addColumn(column);
    }

    // ---------------------------------- Event Handlers

    /**
     * Handle the delete row click event.
     */
    public boolean onDeleteClick() 
    {
        Integer id = deleteLink.getValueInteger();
        getCustomerService().deleteCustomer(id);
        return true;
     }
 
     /**
     * @see Page#onRender()
     */
    public void onRender() 
    {
    	List list = getCustomerService().getCustomersByName();
    	table.setRowList(list);
    }
}

在這個Page程式碼示例中,聲明瞭一個Table控制元件,並添加了一些Column物件。deleteLink ActionLink 控制元件用作“操作”列的裝飾器。當點選此控制元件時,它將呼叫 PageonDeleteClick()方法。最後,我們有 PageonRender()方法,該方法用於在渲染前用行填充 Table 控制元件。

在我們的頁面模板中,我們只需引用 $table 物件,該物件在呼叫其toString()方法時被渲染。

<html>
<head>
$cssImports
</head>
<body>

$table

</body>
</html>
$jsImports

在執行時,Table 將在頁面中渲染為

在此示例中,如果使用者點選“刪除”連結,onDeleteClick()方法將被呼叫,在頁面上刪除客戶記錄。

簡單 Form 示例

[編輯 | 編輯原始碼]

TheFormandField控制元件也是 Click 框架中最常用的控制元件之一。

下面的 SimpleForm 頁面演示瞭如何使用這些控制元件。

在我們的示例程式碼中,頁面的建構函式添加了一個TextField欄位和一個Submit按鈕到表單。頁面方法也設定為表單上的控制元件偵聽器。請注意,在此示例中,頁面的公共form欄位會自動新增到其控制元件列表中。

public class SimpleForm extends Page 
{
    public Form form = new Form();
    public String msg;

    // ------------------------------------------------------------ Constructor

    public SimpleForm() 
    {
        form.add(new TextField("name", true));
        form.add(new Submit("OK"));

        form.setListener(this, "onSubmit");
    }

    // --------------------------------------------------------- Event Handlers

    /**
     * Handle the form submit event.
     */
    public boolean onSubmit() 
    {
        if (form.isValid()) 
        {
            msg = "Your name is "   form.getFieldValue("name");
        }
        return true;
     }
 }

接下來,我們有 SimpleForm 模板 simple-form.htm。Click 應用程式會自動將simple-form.htm模板與SimpleForm類關聯。

<html>
<head>
$cssImports
</head>
<body>

$form

#if ($msg)
  <div id="msgDiv"> $msg </div>
#end

</body>
</html>
$jsImports

第一次請求 SimpleForm 頁面時,$form 物件會自動將其自身渲染為

姓名*

現在,如果使用者沒有輸入他們的姓名,然後點選“確定”按鈕提交表單。ClickServlet 會建立一個新的 SimpleForm 頁面,並處理表單控制元件。

表單控制元件處理其欄位,並確定它無效。然後表單呼叫偵聽器方法onSubmit()方法。由於表單無效,此方法只需返回 true,表單會渲染欄位驗證錯誤。

[# 必須為姓名輸入值]
姓名*

請注意,表單會在釋出和驗證迴圈中自動維護已輸入的狀態。

現在,如果使用者輸入了他們的姓名,然後點選“確定”按鈕,表單將變為有效,並且onSubmit()在頁面的模型中新增一個 msg。它將渲染為

姓名*
您的姓名是 John Masters

高階 Form 示例

[編輯 | 編輯原始碼]

facebook 下面的AdvancedForm頁面提供了一個更高階的演示,演示瞭如何使用 Form、Field 和 FielsSet 控制元件。

首先,我們有一個AdvancedForm類,它在建構函式中設定了一個Form。表單的投資Select列表在頁面的onInit()方法中填充。此時,任何頁面依賴項(例如 CustomerService)都應該可用。

請注意,在此示例中,頁面的公共form欄位會自動新增到其控制元件列表中。該msg欄位被新增到頁面的模型中。

public class AdvancedForm extends Page 
{
    public Form form = new Form();
    public String msg;

    private Select investmentSelect = new Select("investment");

    // ------------------------------------------------------------ Constructor

    public AdvancedForm() 
    {
        FieldSet fieldSet = new FieldSet("Customer");
        form.add(fieldSet);

        TextField nameField = new TextField("name", true);
        nameField.setMinLength(5);
        nameField.setFocus(true);
        fieldSet.add(nameField);

        fieldSet.add(new EmailField("email", true));

        fieldSet.add(investmentSelect);

        fieldSet.add(new DateField("dateJoined", true));
        fieldSet.add(new Checkbox("active"));

        form.add(new Submit("ok", " OK ", this, "onOkClicked"));
        form.add(new Submit("cancel", this, "onCancelClicked"));
    }

    // --------------------------------------------------------- Event Handlers

    /**
     * @see Page#onInit()
     */
    public void onInit() 
    {
        CustomerService customerService = getCustomerService();
        investmentSelect.add(Option.EMPTY_OPTION);
        investmentSelect.addAll(customerService.getInvestmentCatetories());
    }

    /**
     * Handle the OK button click event.
     *
     * @return true
     */
    public boolean onOkClicked() 
    {
        if (form.isValid()) 
        {
            Customer customer = new Customer();
            form.copyTo(customer);

            getCustomerService().saveCustomer(customer);

            form.clearValues();

            msg = "A new customer record has been created.";
         }
         return true;
     }
 
     /**
     * Handle the Cancel button click event.
     *
     * @return false
     */
    public boolean onCancelClicked() 
    {
        setRedirect(HomePage.class);
        return false;
     }
 }

接下來,我們有 AdvancedForm 模板 advanced-form.htm。Click 應用程式會自動將advanced-form.htm模板與AdvancedForm類關聯。

<html>
<head>
$cssImports
</head>
<body>

#if ($msg)
  <div id="msgDiv"> $msg </div>
#end

$form

</body>
</html>
$jsImports

第一次請求 AdvancedForm 頁面時,$form 物件會自動將其自身渲染為

客戶
姓名*
電子郵件*
投資 債券商業房產選項住宅房產股票
加入日期* 日曆
活躍

在此示例中,當用戶點選“確定”按鈕時,onOkClicked()方法被呼叫。如果表單有效,則會建立一個新的客戶物件,並將表單欄位值使用 FormcopyTo()方法複製到新物件中。然後儲存客戶物件,清除表單的欄位值,並向用戶顯示一條資訊訊息。

如果使用者點選“取消”按鈕,則請求將重定向到應用程式的 HopePage。

表單佈局

[編輯 | 編輯原始碼]

在本例中,我們使用表單控制元件來自動渲染表單和欄位的 HTML。對於快速構建螢幕來說,這是一個很棒的功能,並且表單控制元件提供了一些佈局選項。

為了進行細粒度的頁面設計,您可以在頁面模板中專門佈局表單和欄位。

華夏公益教科書