ページネーション ================================================================================ .. only:: html .. contents:: 目次 :depth: 3 :local: Overview -------------------------------------------------------------------------------- 本章では、検索条件に一致するデータをページ分割して表示する方法(ページネーション)について説明する。 | **検索条件に一致するデータが大量になる場合は、ページネーション機能を使用することを推奨する。** | 一度に大量のデータを取得し画面に表示すると、以下3点の問題が発生する可能性がある。 * | サーバ側のメモリ枯渇の発生。 | 単発のリクエストで問題が発生しなくても、同時に複数実行された場合に ``java.lang.OutOfMemoryError`` が発生する可能性がある。 * | ネットワーク負荷の発生。 | 不要なデータがネットワークに流れることで、ネットワーク全体にかかる負荷が高くなり、システム全体のレスポンスタイムに影響を与える可能性がある。 * | 画面のレスポンス遅延の発生。 | 大量のデータを扱う場合、サーバの処理、ネットワークのトラフィック処理、クライアントの描画処理の全てで時間がかかるため、画面のレスポンスが遅くなる可能性がある。 | ページ分割時の一覧画面の表示について ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ページネーション機能を利用してページ分割した場合、以下のような画面になる。 .. figure:: ./images/pagination-overview_screen.png :alt: Screen image of Pagination. :width: 100% .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | ページを移動するためのリンクを表示する。 | リンク押下時には、該当ページを表示するためのリクエストを送信する。この領域を表示するためのJSPタグライブラリを共通ライブラリとして提供している。 * - | (2) - | ページネーションに関連する情報(合計件数、合計ページ数、表示ページ数など)を表示する。 | この領域を表示するためのタグライブラリは存在しないため、JSPの処理として個別に実装する必要がある。 | ページ検索について ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ページネーションを実現する際には、まずサーバ側で行う検索処理をページ検索できるように実装する必要がある。 | 本ガイドラインでは、サーバ側のページ検索は、 Spring Data から提供されている仕組みを利用することを前提としている。 | .. _pagination_overview_page_springdata: Spring Data提供のページ検索機能について """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Spring Dataより提供されているページ検索用の機能は、以下の通り。 .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - 1 - | リクエストパラメータよりページ検索に必要な情報(検索対象のページ位置、取得件数、ソート条件)を抽出し、抽出した情報を ``org.springframework.data.domain.Pageable`` のオブジェクトとしてControllerの引数に引き渡す。 | この機能は、 ``org.springframework.data.web.PageableHandlerMethodArgumentResolver`` クラスとして提供されており、 :file:`spring-mvc.xml` の ```` 要素に追加することで有効となる。 | リクエストパラメータについては、「 :ref:`Note欄 ` 」を参照されたい。 * - 2 - | ページ情報(合計件数、該当ページのデータ、検索対象のページ位置、取得件数、ソート条件)を保持する。 | この機能は、 ``org.springframework.data.domain.Page`` インタフェースとして提供されており、デフォルトの実装クラスとして ``org.springframework.data.domain.PageImpl`` が提供されている。 | **共通ライブラリより提供しているページネーションリンクを出力するためのJSPタグライブラリでは、 Pageオブジェクトから必要なデータを取得する仕様となっている。** * - 3 - | データベースアクセスとしてSpring Data JPAを使用する場合は、RepositoryのQueryメソッドの引数に ``Pageable`` オブジェクトを指定することで、該当ページの情報が ``Page`` オブジェクトとして返却される。 | 合計件数を取得するSQLの発行、ソート条件の追加、該当ページに一致するデータの抽出などの処理が全て自動で行われる。 | データベースアクセスとして、MyBatisを使用する場合は、Spring Data JPAが自動で行ってくれる処理を、Java(Service)及びSQLマッピングファイル内で実装する必要がある。 .. _pagination_overview_pagesearch_requestparameter: .. note:: **ページ検索用のリクエストパラメータについて** Spring Dataより提供されているページ検索用のリクエストパラメータは以下の3つとなる。 .. tabularcolumns:: |p{0.10\linewidth}|p{0.15\linewidth}|p{0.75\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 15 75 * - 項番 - パラメータ名 - 説明 * - 1. - page - | 検索対象のページ位置を指定するためのリクエストパラメータ。 | 値には、0以上の数値を指定する。 | デフォルトの設定では、ページ位置の値は "``0``" から開始する。そのため、1ページ目のデータを取得する場合は "``0``" を、2ページ目のデータを取得する場合は "``1``" を指定する必要がある。 * - 2. - size - | 取得する件数を指定するためのリクエストパラメータ。 | 値には、1以上の数値を指定する。 | ``PageableHandlerMethodArgumentResolver`` の ``maxPageSize`` に指定された値より大きい値が指定された場合は、 ``maxPageSize`` の値が ``size`` の値となる。 * - 3. - sort - | ソート条件を指定するためのパラメータ(複数指定可能)。 | 値には、``{ソート項目名(,ソート順)}`` の形式で指定する。 | ソート順には、``ASC`` 又は ``DESC`` のどちらかの値を指定し、省略した場合は ``ASC`` が適用される。 | 項目名は "``,``" 区切りで複数指定することが可能である。 | 例えば、クエリ文字列として ``sort=lastModifiedDate,id,DESC&sort=subId`` を指定した場合、 ``ORDER BY lastModifiedDate DESC, id DESC, subId ASC`` というOrder By句がQueryに追加される。 .. warning:: **spring-data-commons 1.6.1.RELEASEにおける「size=0」指定時の動作について** terasoluna-gfw-common 1.0.0.RELEASEが依存するspring-data-commons 1.6.1.RELEASEでは、``size=0`` を指定すると条件に一致するレコードを全件取得するという不具合がある。 そのため、大量のレコードが取得対象となる可能性がある場合は、``java.lang.OutOfMemoryError`` が発生する可能性が高くなる。 この問題はSpring Data CommonsのJIRA「`DATACMNS-377 `_」で対応され、spring-data-commons 1.6.3.RELEASEで解消されている。 改修後の動作としては、``size<=0`` を指定した場合は、 sizeパラメータ省略時のデフォルト値が適用される。 terasoluna-gfw-common 1.0.0.RELEASEを使用している場合は、terasoluna-gfw-common 1.0.1.RELEASE以上へバージョンアップする必要がある。 .. warning:: **spring-data-commons 1.6.1.RELEASEにおけるリクエストパラメータに不正な値を指定した際の動作について** terasoluna-gfw-common 1.0.0.RELEASEが依存するspring-data-commons 1.6.1.RELEASEでは、ページ検索用のリクエストパラメータ(page, size, sort)に不正な値を指定した場合、 ``java.lang.IllegalArgumentException`` 又は ``java.lang.ArrayIndexOutOfBoundsException`` が発生し、SpringMVCのデフォルトの設定だとシステムエラー(HTTPステータスコード=500)となってしまうという不具合がある。 この問題はSpring Data CommonsのJIRA「`DATACMNS-379 `_」と「`DATACMNS-408 `_」で対応され、spring-data-commons 1.6.3.RELEASEで解消されている。 改修後の動作としては、不正な値を指定した場合は、 パラメータ省略時のデフォルト値が適用される。 terasoluna-gfw-common 1.0.0.RELEASEを使用している場合は、terasoluna-gfw-common 1.0.1.RELEASE以上へバージョンアップする必要がある。 .. note:: **Spring Data CommonsのAPI仕様の変更に伴う注意点** terasoluna-gfw-common 5.0.0.RELEASE以上が依存するspring-data-commons(1.9.1.RELEASE以上)では、 ページ検索機能用のインタフェース(\ ``org.springframework.data.domain.Page``\ )とクラス(\ ``org.springframework.data.domain.PageImpl``\ と\ ``org.springframework.data.domain.Sort.Order``\ )のAPI仕様が変更になっている。 具体的には、 * \ ``Page``\ インタフェースと\ ``PageImpl``\ クラスでは、\ ``isFirst()``\ と\ ``isLast()``\ メソッドがspring-data-commons 1.8.0.RELEASEで追加、\ ``isFirstPage()``\ と\ ``isLastPage()``\ メソッドがspring-data-commons 1.9.0.RELEASEで削除 * \ ``Sort.Order``\ クラスでは、 \ ``nullHandling``\ プロパティがspring-data-commons 1.8.0.RELEASEで追加 されている。 削除されたAPIを使用している場合はコンパイルエラーとなるので、アプリケーションの修正が必要になる。 加えて、REST APIのリソースオブジェクトとして\ ``Page``\ インタフェース(\ ``PageImpl``\ クラス)を使用している場合は、 JSONやXMLのフォーマットが変わってしまうため、こちらもアプリケーションの修正が必要になるケースがある。 | .. _pagination_overview_paginationlink: ページネーションリンクの表示について ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 共通ライブラリから提供しているJSPタグライブラリを使って出力されるページネーションリンクについて説明する。 | 共通ライブラリからはページネーションリンクを表示するためのスタイルシートの提供は行っていないため、各プロジェクトにて用意すること。 | 以降の説明で使用する画面は、Bootstrap v3.0.0のスタイルシートを適用している。 | ページネーションリンクの構成 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" ページネーションリンクは、以下の要素から構成される。 .. figure:: ./images/pagination-how_to_use_jsp_pagelink_description.png :alt: Structure of the pagination link. :width: 90% :align: center .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | 最初のページに移動するためのリンク。 * - | (2) - | 前のページに移動するためのリンク。 * - | (3) - | 指定したページに移動するためのリンク。 * - | (4) - | 次のページに移動するためのリンク。 * - | (5) - | 最後のページに移動するためのリンク。 | ページネーションリンクは、以下の状態をもつ。 .. figure:: ./images/pagination-how_to_use_jsp_pagelink_description_status.png :alt: Status of the pagination link. :width: 90% :align: center .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (6) - | 現在表示しているページで操作することができないリンクであることを示す状態。 | 具体的には、1ページ目を表示している時の「最初のページに移動するためのリンク」「前のページに移動するためのリンク」と、最終ページを表示している時の「次のページに移動するためのリンク」「最後のページに移動するためのリンク」がこの状態となる。 | 共通ライブラリから提供しているJSPタグライブラリでは、この状態を ``disabled`` と定義している。 * - | (7) - | 現在表示しているページであることを示す状態。 | 共通ライブラリから提供しているJSPタグライブラリでは、この状態を ``active`` と定義している。 | | 共通ライブラリを使って出力されるHTMLは、以下の構造となる。 | 図中の番号は、上記で説明した「ページネーションリンクの構成」と「ページネーションリンクの状態」の項番に対応させている。 - JSP .. code-block:: jsp - 出力されるHTML .. figure:: ./images/pagination-overview_html.png :alt: html of the pagination link. :width: 90% :align: center | ページネーションリンクのHTML構造 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 共通ライブラリを使って出力されるページネーションリンクのHTMLは、以下の構造となる。 - HTML .. figure:: ./images/pagination-overview_html_basic.png :alt: html structure of the pagination link. :width: 100% :align: center - 画面イメージ .. figure:: ./images/pagination-overview_html_basic_screen.png :alt: screen structure of the pagination link. :width: 80% :align: center .. raw:: latex \newpage .. tabularcolumns:: |p{0.10\linewidth}|p{0.70\linewidth}|p{0.20\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 70 20 :class: longtable * - 項番 - 説明 - デフォルト値 * - | (1) - | ページネーションリンクの構成要素をまとめるための要素。 | 共通ライブラリでは、この部分を「Outer Element」と呼び、複数の「Inner Element」を保持する。 | 使用する要素は、JSPタグライブラリのパラメータによって変更することが出来る。 - | ``