トップ 一覧 ヘルプ RSS ログイン

Introductionの変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!!!イントロダクション

Clickは業務アプリケーション開発者のためのシンプルなJ2EE Webアプリケーションフレームワークです。

Clickは[Apache License|http://click.sourceforge.net/docs/LICENSE.txt]に基づくオープンソースプロジェクトです。
Clickは[Apache License|http://incubator.apache.org/click/docs/LICENSE.txt]に基づくオープンソースプロジェクトです。

Clickはサーブレットリクエストを処理するためにイベントベースのプログラミングモデルを採用しており、レスポンスのレンダリングには[Velocity|http://click.sourceforge.net/docs/velocity/velocity.html]を利用します。
Clickはサーブレットリクエストを処理するためにイベントベースのプログラミングモデルを採用しており、レスポンスのレンダリングには[Velocity|http://incubator.apache.org/click/docs/velocity/velocity.html]を利用します。

このフレームワークは[ClickServlet|http://click.sourceforge.net/docs/click-api/net/sf/click/ClickServlet.html]というリクエストディスパッチャとして振る舞う単一のサーブレットを使用します。リクエストが到達するとClickServletはリクエストを処理するために[Page|http://click.sourceforge.net/docs/click-api/net/sf/click/Page.html]オブジェクトを生成し、その後、結果をレンダリングするためにVelocityテンプレートを使用します。
このフレームワークは[ClickServlet|http://incubator.apache.org/click/docs/click-api/org/apache/click/ClickServlet.html]というリクエストディスパッチャとして振る舞う単一のサーブレットを使用します。リクエストが到達するとClickServletはリクエストを処理するために[Page|http://incubator.apache.org/click/docs/click-api/org/apache/click/Page.html]オブジェクトを生成し、その後、結果をレンダリングするためにVelocityテンプレートを使用します。

ページはリクエストごとに新たなインスタンスが生成され、シンプルかつスレッドセーフなプログラミング環境を提供します。

Clickがどのように動作するのかを理解する最もよい手段は実際にサンプルを見てみることでしょう。

* [Hello World|http://amateras.sourceforge.jp/cgi-bin/fswiki/wiki.cgi/click?page=Introduction#p1] - いつものHello Worldを表示するサンプルです
* [Control Listener|http://amateras.sourceforge.jp/cgi-bin/fswiki/wiki.cgi/click?page=Introduction#p2] - ActionLink コントロールのリスナのサンプルです
* [Simple Table|http://amateras.sourceforge.jp/cgi-bin/fswiki/wiki.cgi/click?page=Introduction#p3] - Table のサンプルです
* [Advanced Table|http://amateras.sourceforge.jp/cgi-bin/fswiki/wiki.cgi/click?page=Introduction#p4] - 高度な Table のサンプルです
* [Simple Form|http://amateras.sourceforge.jp/cgi-bin/fswiki/wiki.cgi/click?page=Introduction#p5] - Form のサンプルです
* [Advanced Form|http://amateras.sourceforge.jp/cgi-bin/fswiki/wiki.cgi/click?page=Introduction#p6] - 高度な Form のサンプルです

!!Hello Worldのサンプル

ClickにおけるHello Worldサンプルは以下のようになります。

まず最初に用意するのはHelloWorldページクラスです:

{{code java
package examples.page;

import java.util.Date;
import net.sf.click.Page;
import org.apache.click.Page;

public HelloWorld extends Page {

    public Date time = new Date();

}
}}

次に'''hello-world.htm'''というページテンプレートを作成します:

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

最後に'''hello-world.htm'''へのリクエストをHelloWorldページクラスへマッピングするようアプリケーションに伝えるためのclick.xmlという設定ファイルを用意します。

{{code xml
<click-app>  
  <pages package="examples.page"/> 
</click-app> 
}}

実行時にClickServletは GET '''hello-world.htm''' というリクエストをexample.page.HelloWorldクラスにマッピングし、新しいインスタンスを作成します。HelloWorldページは新しいpublic Dateオブジェクトを作成します。このDateオブジェクトは'''time'''という名前で自動的にページモデルに追加されます。

ページモデルはテンプレートとマージされ、'''$time'''というパラメータはDateオブジェクトで置き換えられます。Velocityは以下のようにマージされたテンプレートをレンダリングします。

{{ref_image hello-1.4-RC1.png}}

!!Control Listener のサンプル
ClickはUI機能を提供する[Control|http://amateras.sourceforge.jp/cgi-bin/fswiki/wiki.cgi/click?page=Controls]ライブラリも提供しています。

その中でよく使われるもののひとつに、[[ActionLink]]コントロールがあります。これは、Pageオブジェクトのメソッドを呼び出すことができるHTMLリンクを生成します。

{{code java
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のインスタンスを生成し、そのリスナにページのメソッドであるMyLinkClick()を指定しています。このページを訪れたユーザーが、この'''myLink'''コントロールをクリックすると、onMyLinkClick()メソッドが実行されます。

コントロールのリスナメソッドは、どのような名前でも構わないのですが、返り値はbooleanである必要があります。その値によって、ページのイベント処理が続行されるべきかどうかを指定します。このコントロールリスナパターンは、匿名内部クラスを定義する必要も無く、手軽なアクションリスナを提供します。

上の例に話を戻すと、このページのテンプレートでHTMLのリンクを定義し、
'''myLink'''コントロールをリンクのhref属性として出力します。

{{code html
<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>
}}

このページを実際に実行すると、以下のようにレンダリングされます。

{{ref_image control-listener1.png}}

このリンクをクリックすると、onMyLinkClick()メソッドが実行されます。
このメソッドは、'''msg'''の値を作成し、その値がページに表示されます。

{{ref_image control-listener2.png}}

!!!Table のサンプル

Clickのコントロールの中で特に便利なのが[[Table]]コントロールです。

customersページにおけるTableの使用例が以下になります。

{{code java
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のclassをセットし、そしてテーブルの列である[[Column]]オブジェクトを定義しています。
このコンストラクタの中で、列の名前を指定しています。これはテーブルの列のヘッダーとして用いられ、またレンダリングすべき行オブジェクトのプロパティを指定します。

そして最後に、テーブルへデータを配置します。PageのonRender()メソッドをオーバーライドしレンダリングする前にテーブルに行のリストをセットします。

ページのテンプレート側では、toString()メソッドが呼ばれてレンダリングされる'''$table'''オブジェクトを単に参照するだけです。

{{code html
<html>
<head>
  $imports
</head>
<body>
  
  $table
    
</body>
</html> 
}}

ここでは'''$import'''も記述していますが、これによりテーブルがスタイルシートのヘッダーをインクルードできることになります。

このテーブルは、実行時に以下のようにレンダリングされます。

{{ref_image simple-table.png}}

!!高度なテーブルのサンプル

Tableコントロールは、以下の機能もあわせて提供しています。

* 自動レンダリング
* カラムの整形およびカスタムレンダリング
* 自動ページネイション
* リンクコントロールの利用

以下のコードは、より高度なテーブルの例になります。

{{code java
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);
    }
} 
}}

このページでは、Tableコントロールが宣言されており、いくつかの[[Column]]オブジェクトがテーブルのカラムとして追加されています。[[ActionLink]]のインスタンスであるdeleteLinkは、"Action"カラムのデコレーターのひとつとして使われています。このコントロールがクリックされたときにこのページのonDeleteClick()メソッドが呼び出されます。最後にonRender()メソッドがありますが、実際に出力される前にテーブルコントロールの各行のデータを取り出しています。

ページテンプレートでは、toString()メソッドが呼ばれてレンダリングされる
'''$table'''オブジェクトを単に参照するだけです。

{{code html
<html>
<head>
  $imports
</head>
<body>
  
  $table
    
</body>
</html> 
}}

実行するとこのTableは以下のようにレンダリングされます。

{{ref_image advanced-table.png}}

この例では、DeleteリンクをクリックするとonDeleteClick()メソッドが呼び出されてその行に相当するcustomerのレコードが削除されます。

!!Formのサンプル

[[Form]]と[Field|http://click.sourceforge.net/docs/click-api/net/sf/click/control/Field.html]コントロールもまた、Click Frameworkではよく使用されます。

以下のSimpleFormページは、これらの使用例になります。

このサンプルコードのでは、ページのコンストラクタで[[TextField]]と[[Submit]]ボタンをひとつずつフォームに追加しています。
ページのメソッドは、フォームのコントロールリスナとしてセットされています。
また、この例ではページのpublicな'''form'''というフィールドが自動的にコントロールのリストに追加されることに注意してください。

{{code java
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クラスを関連付けます。
{{code html
<html>
<head>
  $imports
</head>
<body>
  
  $form
  
#if ($msg)
  <div id="msgDiv"> $msg </div>
#end
    
</body>
</html> 
}}

SimpleForm が最初にリクエストされたとき、'''$form'''は以下のように自分自身をレンダリングします:

{{ref_image simple-form1.png}}

ユーザがユーザ名を入力せずにOKボタンを押してフォームを送信したとします。
ClickServletは新しいSimpleFormページを作成し、フォームコントロールを処理します。

フォームコントロールは各フィールドを処理し、エラーがあることを検出します。
次にOKボタンが押されたことによってonSubmit()イベントハンドラが呼び出されます。
しかし、フォームにエラーがあるのでこのメソッドはtrueを返し、フォームはフィールドのバリデーションエラーをレンダリングします。

{{ref_image simple-form2.png}}

ポストやバリデーションのサイクルでは、formが入力された状態を自動的に保持していることに注意してください。

さて、ユーザーがユーザー名を入力しOKボタンをクリックすると、
formは受理されてonSubmit()メソッドでmsgをページモデルに追加します。
以下のようにレンダリングされます。

{{ref_image simple-form3.png}}

!!高度なフォームの使用例

以下のAdvancedFormページは、Form、Field、そしてFieldSetを利用した例になります。

まず、コンストラクタで[[Form]]のセットアップを実施します。このフォームの"investment"項目は
[[Select]]であり、ページのonInit()メソッドで選択項目を生成しています。
このonInit()の時点で、CustomerServiceのようなページの依存関係にあるものも利用可能になっているはずです。

この例では、ページのパブリックなフィールドである'''form'''が自動的にコントロールのリストに追加されています。
また同様に'''msg'''フィールドはページのモデルに追加されます。

{{code java
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クラスに結び付けます。

{{code html
<html>
<head>
   $imports
</head>
<body>

#if ($msg)
  <div id="msgDiv"> $msg </div>
#end
  
   $form
    
</body>
</html> 
}}

このページが最初にリクエストを受けたときには、'''$form'''は以下のように出力されます。

{{ref_image advanced-form.png}}

この例でOKボタンを押すと、onOkClicked()メソッドが実行されます。onOkClickedメソッドの中で、formがvalidならば、新しいcustomerオブジェクトが生成され、Formの[copyTo()|http://click.sourceforge.net/docs/click-api/net/sf/click/control/Form.html#copyTo(java.lang.Object)]メソッドを使いformの各フィールドの値は新しいオブジェクトにコピーされます。そしてcustomerオブジェクトは保存され、各フィールドの値はクリアされ、通知用メッセージをセットしています。

もしCancelボタンを押すと、リクエストはHomePageへリダイレクトされます。

!フォームのレイアウトについて

このサンプルではフォームとフィールドのHTMLを自動的にレンダリングするためにフォームコントロールを使用しました。
これは画面を迅速に構築するためのとても便利な機能です。そして、フォームコントロールは多くのレイアウトオプションを提供します。
詳細については[Clickのサンプル|http://click.sourceforge.net/docs/examples.html]のForm Propertiesデモを参照してください。

詳細なページデザインを行なう必要がある場合、ページテンプレートにおいてフォームやフィールドのレイアウトを明示的に指定することもできます。より詳細な情報については[Form|http://click.sourceforge.net/docs/click-api/net/sf/click/control/Form.html#form-layout]クラスのJavadocを参照してください。