2009年11月12日木曜日

JSF 2.0/h:datatable/Paginator

h:datatable の ページ切り替えを考えてみた。 基本的には、以下のような Paginator になるんじゃないだろうか。
package study.jsf.pagination;

import java.util.List;

public abstract class Paginator<T> {
   private final int size; 
   private int page = 0;

   public Paginator(int size) {
      this.size = size;
   }
   public abstract List<T> currentElements();

   public abstract int itemsCount();
   
   public int start() {
      return page * size; 
   }
   public int size() { 
      return size; 
   }
   public boolean isHasNextPage() {
      return (page + 1) * size() + 1 <= itemsCount();
   }
   public void nextPage() {
      if (isHasNextPage()) page++;
   }
   public boolean isHasPreviousPage() {
      return page > 0;
   }
   public void previousPage() {
      if (isHasPreviousPage()) page--;
   }
   public int getPageSize() { 
      return size(); 
   }
}
ManagedBean など、これを使う側で itemsCount()と currentElements()メソッドを実装し、型パラメータに具体型を与える。適当すぎるサンプルだが、例えば以下のように書く。
package study.jsf.pagination;

import 略

@ManagedBean(name="memberList")
@SessionScoped
public class PersonListBean {
   private static final List MEMBERS_LIST = Arrays.asList(
      new Person(1, "Wilhelm"),
      new Person(2, "Hendrik"),   
      new Person(3, "Pieter"),   
      new Person(4, "Antoine"),
      new Person(5, "Pierre"),
      new Person(6, "Marie"),
      new Person(7, "John"),
      new Person(8, "Philipp")   
   ); 
   private Paginator paginator = new Paginator(3) {
      @Override
      public List currentElements() {
         return MEMBERS_LIST.subList(start(), 
               Math.min(start() + size(), itemsCount()));
      }
      @Override
      public int itemsCount() {
         return MEMBERS_LIST.size();
      }
   };
   public Paginator getPaginator() {
      return paginator;
   }
   public List getMembers() {
      return paginator.currentElements();
   }
   public void next() {
      paginator.nextPage();
   }
   public void previous() {
      paginator.previousPage();
   }
}
faces ファイルはこんな感じになる
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:h="http://java.sun.com/jsf/html">
<h:head>
   <title>ajax-dataTable</title>
</h:head>
<h:body>
  <h:form>
   <h:dataTable 
      id="partyTable" 
      value="#{memberList.members}"
      var="member">
     <h:column>#{member.id}</h:column>
     <h:column>#{member.name}</h:column>
   </h:dataTable>
   <h:commandLink id="prevLink" action="#{memberList.previous}"
      value="前 #{memberList.paginator.pageSize}件"
      rendered="#{memberList.paginator.hasPreviousPage}">
      <f:ajax execute="@this" render="@form"/>
   </h:commandLink>
   &#160; 
   <h:commandLink
      id="nextLink" action="#{memberList.next}"
      value="次#{memberList.paginator.pageSize}件"
      rendered="#{memberList.paginator.hasNextPage}">
      <f:ajax execute="@this" render="@form"/>
   </h:commandLink>
  </h:form>
</h:body>
</html>
実行すると、Person オブジェクトから 3つずつ(3ページ目は2つ)がテーブルに表示され、また 3ページ目以外では「次3件」リンクが、1ページ目以外では「前3件」リンクが表示される。 あと考える事は以下のような感じか
  • currentElements() は List<T>じゃなくて、DataModel<T>を返す方がいいかもしれない。
  • 呼び出し側では無駄に currentElements()を呼ばずにすむような仕組みを考える必要があるかも

1 件のコメント:

師子乃 さんのコメント...

初めまして。

ページネーター、必要な機能ですが、始めから作るのは結構大変ですのでありがたいですね。

コメントを投稿