2008年6月21日土曜日

ZK: Pagingコンポーネントでライブデータ表示

Smalltaksの記事Use Load-On-Demand to Handle Huge Dataを試してみました。
リストボックスに一度に大量なデータを表示するとWEBアプリにもサーバにも大きな負担がかかります。
Pagingコンポーネントを明示的に使いオンデマンドでページ単位にクエリーを実行し、取得したライブデータでリストボックスの表示を効果的に処理する方法が紹介されていました。

<window
title="Listbox with Paging Performance using ZK version: ${desktop.webApp.version}"
border="normal" use="sample.ui.EmployeeUI"
xmlns:zk="http://www.zkoss.org/2005/zul"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd">
<zk:toolbarbutton href="/" label="Back" />
<zk:listbox id="listEmployee" width="350px" checkmark="true">
<zk:listhead sizable="true">
<zk:listheader label="ID" sort="auto" />
<zk:listheader label="Full Name" sort="auto" />
<zk:listheader label="User Name" sort="auto" />
</zk:listhead>
</zk:listbox>
<!-- 明示的にpagingコンポーネントを使用する。 -->
<zk:paging id="pageEmployee" pageSize="30" />
</window>

Windowを継承したクラスでインターフェースAfterComposeを実装します。
afterComposeメソッドでは
  • データのトータル行数をセット
  • 最初のページにデータを表示
  • pagingコンポーネントに onPaging イベントリスナを登録
    を行います。

    public class EmployeeUI extends SimpleWindow implements AfterCompose {
    private final String LISTBOX_ID= "listEmployee"; //zulファイルの listbox コンポーネントの id
    private final String PAGING_ID = "pageEmployee"; //zulファイルの paging コンポーネントのid
    private JdbcManager jdbcManager; //Seasar変数

    public EmployeeUI(){
    DelegatingVariableResolver variableResolver = new DelegatingVariableResolver();
    jdbcManager = (JdbcManager)variableResolver.resolveVariable("jdbcManager");
    }

    /**
    * AfterComposeインターフェースのafterComposeメソッドはコンポーネント作成段階で処理される。
    * コンポーネントを作成した直後に初期化できパフォーマンスの改善に役立つ。
    *
    */
    public void afterCompose() {
    Paging page = getPaging(PAGING_ID);

    //データのトータル行数を取得
    page.setTotalSize((int)jdbcManager.from(Employee.class).getCount());

    final int PAGE_SIZE = page.getPageSize();

    // Listboxに最初のページを表示 オフセット--0 行数---PAGE_SIZE
    redraw(0, PAGE_SIZE);

    // onPagingイベントリスナの登録 決まり文句
    page.addEventListener("onPaging", new EventListener() {
    public void onEvent(Event event) {
    PagingEvent pageEvent = (PagingEvent) event;
    int pageNo = pageEvent.getActivePage();
    int offset = pageNo * PAGE_SIZE;

    // クリックされたページ番号でライブデータを取得し再表示
    redraw(offset, PAGE_SIZE);
    }
    });

    }


    /**
    * afterCompose及びonPagingイベントリスナから呼び出されListboxを描画する。
    * コールされる度にクエリを実行しデータベースからライブデータを取得する。
    *
    * @param firstResult オフセット
    * @param maxResults 行数
    */
    private void redraw(int firstResult, int maxResults) {
    Listbox listBox = getListbox(LISTBOX_ID);
    listBox.getItems().clear();

    // データ取得
    List<Employee> emps = jdbcManager.from(Employee.class)
    .orderBy("id") // 問い合わせ結果をページングするにはorder by が必要
    .offset(firstResult)
    .limit(maxResults)
    .getResultList();
    // 表示
    for (Employee employee : emps) {
    Listitem li = new Listitem();
    li.setValue(employee);
    li.appendChild(new Listcell("" + employee.id));
    li.appendChild(new Listcell(employee.fullname));
    li.appendChild(new Listcell(employee.username));
    listBox.appendChild(li);
    }
    }
    }


    大量なデータでも paging コンポーネントを用いライブデータで処理を行うとアプリの動作は非常に軽快ですね。
  • 0 件のコメント: