コードリスト
================================================================================

.. only:: html

 .. contents:: 目次
    :depth: 4
    :local:

Overview
--------------------------------------------------------------------------------

コードリストとは、「コード値(value)とその表示名(label)」の集合である。

画面のセレクトボックスなどコード値を画面で表示する際のラベルへのマッピング表として利用される。

共通ライブラリでは、

* xmlファイルやDBに定義されたコードリストをアプリケーション起動時に読み込みキャッシュする機能
* ThymeleafのテンプレートHTMLやJavaクラスからコードリストを参照する機能
* コードリストを用いて入力チェックする機能

を提供している。

また、応用的な使い方として、

* コードリストの国際化対応
* キャッシュされたコードリストのリロード

もサポートしている。

.. note::

    標準でリロードが可能なのは、DBに定義されたコードリストを使用する場合のみである。

|

.. _listOfCodeList:

共通ライブラリでは、以下のコードリスト実装クラスを提供している。

.. tabularcolumns:: |p{0.50\linewidth}|p{0.30\linewidth}|p{0.20\linewidth}|
.. list-table:: **コードリスト種類一覧**
   :header-rows: 1
   :widths: 50 30 20

   * - 種類
     - 内容
     - Reloadable
   * - ``org.terasoluna.gfw.common.codelist.SimpleMapCodeList``
     - xmlファイルに直接記述した内容を使用する。
     - NO
   * - ``org.terasoluna.gfw.common.codelist.NumberRangeCodeList``
     - 数値の範囲のリストを作成する際に使用する。
     - NO
   * - ``org.terasoluna.gfw.common.codelist.JdbcCodeList``
     - DBから対象のコードをSQLで取得して使用する。
     - YES
   * - ``org.terasoluna.gfw.common.codelist.EnumCodeList``
     - \ ``Enum``\ クラスに定義した定数からコードリストを作成する際に使用する。
     - NO
   * - ``org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList``
     - 国際化に対応し、java.util.Localeに応じたコードリストを使用する。
     - NO
   * - ``org.terasoluna.gfw.common.codelist.i18n.SimpleReloadableI18nCodeList``
     - 国際化に対応し、java.util.Localeに応じた更新可能なコードリストを使用する。(**5.4.2から追加**)
     - YES

| 上記コードリストのインタフェースについて、共通ライブラリに ``org.terasoluna.gfw.common.codelist.CodeList`` を提供している。
| また国際化に対応しているコードリストのインタフェースについて、``org.terasoluna.gfw.common.codelist.i18n.I18nCodeList`` を提供している。

共通ライブラリで提供しているコードリストのクラス図構成を以下に示す。

.. figure:: ./images/codelist-class-diagram.png
   :alt: codelist class diagram
   :align: center

   **Picture - Image of codelist class diagram**

|

How to use
--------------------------------------------------------------------------------

本項では、各種コードリストを使用する上での設定や実装方法を記述する。

* :ref:`codelist-simple`
* :ref:`codelist-number`
* :ref:`codelist-jdbc`
* :ref:`codelist-enum`
* :ref:`codelisti18n`
* :ref:`codelist-display-label`
* :ref:`codelist-validate`

|

.. _codelist-simple:

SimpleMapCodeListの使用方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``org.terasoluna.gfw.common.codelist.SimpleMapCodeList`` とは、
xmlファイルに定義したコード値をアプリケーション起動時に読み込み、そのまま使用するコードリストである。

**SimpleMapCodeListのイメージ**

.. figure:: ./images/codelist-simple.png
   :alt: codelist simple
   :width: 100%

|

コードリスト設定例
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

**bean定義ファイル(xxx-codelist.xml)の定義**

bean定義ファイルは、コードリスト用に作成することを推奨する。

.. code-block:: xml
   :emphasize-lines: 1,4

    <bean id="CL_ORDERSTATUS" class="org.terasoluna.gfw.common.codelist.SimpleMapCodeList"> <!-- (1) -->
        <property name="map">
            <util:map>
                <entry key="1" value="Received" /> <!-- (2) -->
                <entry key="2" value="Sent" />
                <entry key="3" value="Cancelled" />
            </util:map>
        </property>
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | SimpleMapCodeListクラスをbean定義する。
       | beanIDは、後述する ``org.terasoluna.gfw.web.codelist.CodeListInterceptor`` のIDパターンに合致する名称にすること。
   * - | (2)
     - | Mapの Key、Valueを定義する。
       | map-class属性を省略した場合、 ``java.util.LinkedHashMap`` で登録されるため、上記例では、「名前と値」が、登録順にMapへ保持される。

|

**bean定義ファイル(xxx-domain.xml)の定義**

コードリスト用bean定義ファイルを作成後、既存bean定義ファイルにimportを行う必要がある。

.. code-block:: xml
   :emphasize-lines: 1

    <import resource="classpath:META-INF/spring/projectName-codelist.xml" /> <!-- (3) -->
    <context:component-scan base-package="com.example.domain" />

    <!-- omitted -->

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (3)
     - | コードリスト用bean定義ファイルをimportする。
       | component-scanしている間にimport先の情報が必要な場合があるため、
       | importは ``<context:component-scan base-package="com.example.domain" />`` より上で設定する必要がある。

|

.. _clientSide:

テンプレートHTMLでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

共通ライブラリから提供しているインタセプターを用いることで、
リクエスト属性に自動的に設定し、テンプレートHTMLからコードリストを容易に参照できる。

**bean定義ファイル(spring-mvc.xml)の定義**

.. code-block:: xml
   :emphasize-lines: 3,5,6

    <mvc:interceptors>
      <mvc:interceptor>
        <mvc:mapping path="/**" /> <!-- (1) -->
        <bean
          class="org.terasoluna.gfw.web.codelist.CodeListInterceptor"> <!-- (2) -->
          <property name="codeListIdPattern" value="CL_.+" /> <!-- (3) -->
        </bean>
      </mvc:interceptor>

      <!-- omitted -->

    </mvc:interceptors>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | 適用対象のパスを設定する。
   * - | (2)
     - | CodeListInterceptor クラスをbean定義する。
   * - | (3)
     - | 自動でリクエスト属性に設定する、コードリストのbeanIDのパターンを設定する。
       | パターンには ``java.util.regex.Pattern`` で使用する正規表現を設定すること。
       | 上記例では、idが"CL\_XXX"形式で定義されているデータのみを対象とする。その場合、idが"CL\_"で始まらないbean定義は取り込まれない。
       | "CL\_"で定義したbeanIDは、リクエスト属性に設定されるため、テンプレートHTMLで容易に参照できる。
       |
       | \ ``codeListIdPattern``\ プロパティは省略可能である。
       | \ ``codeListIdPattern``\ を省略した場合は、すべてのコードリスト(\ ``org.terasoluna.gfw.common.codelist.CodeList``\ インタフェースを実装しているbean)がリクエスト属性に設定される。

.. warning:: **例外発生時のコードリスト利用について**

    terasoluna-gfw-common 5.4.2.RELEASEより、Controllerのハンドラメソッドで例外が発生し \ ``@ExceptionHandler``\ や \ ``SystemExceptionResolver``\ で例外ハンドリングを行なった場合は、コードリストがリクエストスコープに登録されなくなった。
    これは、 \ ``CodeListInterceptor``\ が \ ``HandlerInterceptor#postHandle``\ メソッドでコードリストの登録を行うように変更されたためである。

    例外時に遷移する画面でコードリストを利用したい場合は、ハンドラメソッドで例外を捕捉(try-catch)するか、 :ref:`directRefCodeList` を利用してコードリストを取得することを検討されたい。
    
    例外ハンドリングの方法については、 :ref:`exception-handling-method-label` を参照されたい。

|

**テンプレートHTML実装例**

.. code-block:: html

  <select th:field="*{orderStatus}">
      <option value="">--Select--</option> <!--/* (4) */-->
      <option th:each="order : ${CL_ORDERSTATUS}" th:value="${order.key}" th:text="${order.value}"></option> <!--/* (5) */-->
  </select>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (4)
     - | セレクトボックスの先頭にダミーの値を設定する場合、valueに空文字を指定すること。
   * - | (5)
     - | コードリストを定義したbeanIDを指定する。

**出力HTML**

.. code-block:: html

  <select id="orderStatus" name="orderStatus">
     <option value="">--Select--</option>
     <option value="1">Received</option>
     <option value="2">Sent</option>
     <option value="3">Cancelled</option>
  </select>

**出力画面**

.. figure:: ./images/codelist_selectbox.png
   :alt: codelist selectbox
   :width: 40%

|

.. _serverSide:

Javaクラスでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

Javaクラスでコードリストを利用する場合、 ``javax.inject.Inject`` アノテーションと、
``javax.inject.Named`` アノテーションを設定してコードリストをインジェクションする。
``@Named`` にコードリスト名を指定する。

.. code-block:: java

  import javax.inject.Named;

  import org.terasoluna.gfw.common.codelist.CodeList;

  @Service
  public class OrderServiceImpl implements OrderService {

      @Inject
      @Named("CL_ORDERSTATUS")
      CodeList orderStatusCodeList; // (1)

      public boolean existOrderStatus(String target) {
          return orderStatusCodeList.asMap().containsKey(target); // (2)
      }
  }

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | beanIDが、"CL_ORDERSTATUS"であるコードリストをインジェクションする。
   * - | (2)
     - | CodeList#asMapメソッドでコードリストを ``java.util.Map`` 形式で取得する。

|

.. _codelist-number:

NumberRangeCodeListの使用方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``org.terasoluna.gfw.common.codelist.NumberRangeCodeList`` とは、
アプリケーション起動時に、指定した数値の範囲をリストにするコードリストである。
主に数だけのセレクトボックス、月や日付などのセレクトボックスに使用することを想定している。

**NumberRangeCodeListのイメージ**

.. figure:: ./images/codelist-number.png
   :alt: codelist number
   :width: 100%

.. tip::

    NumberRangeCodeListはアラビア数字のみ対応しており、漢数字やローマ数字には対応していない。
    漢数字やローマ数字を表示したい場合はJdbcCodeList、SimpleMapCodeListに定義することで対応可能である。

|

NumberRangeCodeListには、以下の特徴がある。

#. Fromの値をToの値より小さくする場合、昇順にinterval分増加した値をFrom~Toの範囲分リストにする。
#. Toの値をFromの値より小さくする場合、降順にinterval分減少した値をTo~Fromの範囲分リストにする。
#. 増加分(減少分)はintervalを設定することで変更できる。

|

ここでは、昇順の\ ``NumberRangeCodeList``\ について説明をする。
降順の\ ``NumberRangeCodeList``\とインターバルの変更方法については、「:ref:`CodeListAppendixNumberRangeCodeListVariation`」を参照されたい。

|

コードリスト設定例
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

Fromの値をToの値より小さくする(From < To)場合の実装例を、以下に示す。

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_MONTH"
        class="org.terasoluna.gfw.common.codelist.NumberRangeCodeList"> <!-- (1) -->
        <property name="from" value="1" /> <!-- (2) -->
        <property name="to" value="12" /> <!-- (3) -->
        <property name="valueFormat" value="%d" /> <!-- (4) -->
        <property name="labelFormat" value="%02d" /> <!-- (5) -->
        <property name="interval" value="1" /> <!-- (6) -->
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | NumberRangeCodeListをbean定義する。
   * - | (2)
     - | 範囲開始の値を指定する。省略した場合、"0"が設定される。
   * - | (3)
     - | 範囲終了の値を設定する。指定必須。
   * - | (4)
     - | コード値のフォーマット形式を設定する。フォーマット形式は ``java.lang.String.format`` の形式が使用される。
       | 省略した場合、"%s"が設定される。
   * - | (5)
     - | コード名のフォーマット形式を設定する。フォーマット形式は ``java.lang.String.format`` の形式が使用される。
       | 省略した場合、"%s"が設定される。
   * - | (6)
     - | 増加する値を設定する。省略した場合、"1"が設定される。

|

テンプレートHTMLでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

テンプレートHTMLでコードリストを使用する方法については、前述した、:ref:`テンプレートHTMLでのコードリスト使用<clientSide>` を参照されたい。

**テンプレートHTML実装例**

.. code-block:: html

  <select th:field="*{depMonth}">
      <option th:each="month : ${CL_MONTH}" th:value="${month.key}" th:text="${month.value}"></option>
  </select>

**出力HTML**

.. code-block:: html

  <select id="depMonth" name="depMonth">
    <option value="1">01</option>
    <option value="2">02</option>
    <option value="3">03</option>
    <option value="4">04</option>
    <option value="5">05</option>
    <option value="6">06</option>
    <option value="7">07</option>
    <option value="8">08</option>
    <option value="9">09</option>
    <option value="10">10</option>
    <option value="11">11</option>
    <option value="12">12</option>
  </select>

**出力画面**

.. figure:: ./images/codelist_numberrenge.png
   :alt: codelist numberrenge
   :width: 5%

|

Javaクラスでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

Javaクラスでコードリストを使用する方法については、 :ref:`Javaクラスでのコードリスト使用<serverSide>` を参照されたい。

|

.. _codelist-jdbc:

JdbcCodeListの使用方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

| ``org.terasoluna.gfw.common.codelist.JdbcCodeList`` とは、アプリケーション起動時にDBから値を取得し、コードリストを作成するクラスである。
| ``JdbcCodeList`` はアプリケーション起動時にキャッシュを作るので、リスト表示時はDBアクセスによる遅延がない。

| 起動時の読み込み時間を抑えたいならば、取得数の上限を設定するとよい。
| ``JdbcCodeList`` には ``org.springframework.jdbc.core.JdbcTemplate`` を設定するフィールドがある。
| ``JdbcTemplate`` の ``fetchSize`` に上限を設定すれば、その分だけのレコードが起動時に読み込まれる。  
| なお、取得する値はリロードにより動的に変更できる。詳細は :ref:`codeListTaskScheduler` 参照されたい。

**JdbcCodeListのイメージ**

.. figure:: ./images/codelist-jdbc.png
   :alt: codelist simple
   :width: 100%

|

コードリスト設定例
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

**テーブル(authority)の定義**

.. tabularcolumns:: |p{0.40\linewidth}|p{0.60\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 40 60

   * - authority_id
     - authority_name
   * - | 01
     - | STAFF_MANAGEMENT
   * - | 02
     - | MASTER_MANAGEMENT
   * - | 03
     - | STOCK_MANAGEMENT
   * - | 04
     - | ORDER_MANAGEMENT
   * - | 05
     - | SHOW_SHOPPING_CENTER

|

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="jdbcTemplateForCodeList" class="org.springframework.jdbc.core.JdbcTemplate" > <!-- (1) -->
        <property name="dataSource" ref="dataSource" />
        <property name="fetchSize" value="${codelist.jdbc.fetchSize:1000}" /> <!-- (2) -->
    </bean>

    <bean id="AbstractJdbcCodeList"
        class="org.terasoluna.gfw.common.codelist.JdbcCodeList" abstract="true"> <!-- (3) -->
        <property name="jdbcTemplate" ref="jdbcTemplateForCodeList" /> <!-- (4) -->
    </bean>

    <bean id="CL_AUTHORITIES" parent="AbstractJdbcCodeList" > <!-- (5) -->
        <property name="querySql"
            value="SELECT authority_id, authority_name FROM authority ORDER BY authority_id" /> <!-- (6) -->
        <property name="valueColumn" value="authority_id" /> <!-- (7) -->
        <property name="labelColumn" value="authority_name" /> <!-- (8) -->
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90
   :class: longtable

   * - 項番
     - 説明
   * - | (1)
     - | ``org.springframework.jdbc.core.JdbcTemplate`` クラスをbean定義する。
       | 独自に ``fetchSize`` を設定するために必要となる。
   * - | (2)
     - | ``fetchSize`` を設定する。
       | ``fetchSize`` のデフォルト設定が、全件取得になっている場合があるため適切な値を設定すること。
       | ``fetchSize`` の設定が全件取得のままだと、 ``JdbcCodeList`` の読み込む件数が大きい場合に、DBからリストを取得する際の処理性能が落ちてしまい、アプリケーションの起動時間が長期化する可能性がある。
   * - | (3)
     - | ``JdbcCodeList`` の共通bean定義。
       | 他の ``JdbcCodeList`` の共通部分を設定している。そのため、基本 ``JdbcCodeList`` のbean定義はこのbean定義を親クラスに設定する。
       | abstract属性をtrueにすることで、このbeanはインスタンス化されない。
   * - | (4)
     - | (1)で設定した ``jdbcTemplate`` を設定。
       | ``fetchSize`` を設定した ``JdbcTemplate`` を、 ``JdbcCodeList`` に格納している。
   * - | (5)
     - | ``JdbcCodeList`` のbean定義。
       | parent属性を(3)のbean定義を親クラスとして設定することで、 ``fetchSize`` を設定した ``JdbcCodeList`` が設定される。
       | このbean定義では、クエリに関する設定のみを行い、必要なCodeList分作成する。
   * - | (6) 
     - | querySqlプロパティに取得するSQLを記述する。その際、 **必ず「ORDER BY」を指定し、順序を確定させること。**
       | 「ORDER BY」を指定しないと、取得する度に順序が変わってしまう。
   * - | (7)
     - | valueColumnプロパティに、MapのKeyに該当する値を設定する。この例ではauthority_idを設定している。
   * - | (8)
     - | labelColumnプロパティに、MapのValueに該当する値を設定する。この例ではauthority_nameを設定している。      

.. raw:: latex

   \newpage

|

テンプレートHTMLでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
| テンプレートHTMLでコードリストを使用する方法については、前述した :ref:`テンプレートHTMLでのコードリスト使用<clientSide>` を参照されたい。

**テンプレートHTML実装例**

.. code-block:: html

  <span th:each="authority : ${CL_AUTHORITIES}">
      <input type="checkbox" th:field="*{authorities}" th:value="${authority.key}">
      <label th:for="${#ids.prev('authorities')}" th:text="${authority.value}"></label> <!--/* (9) */-->
  </span>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90
   :class: longtable

   * - 項番
     - 説明
   * - | (9)
     - | ``#ids.prev`` メソッドを使用して、``input`` タグの ``id`` 名と対応付けることができる。詳細は、 :ref:`#ids.prevメソッドについて<Validation_ids_prev_method>` を参照されたい。

**出力HTML**

.. code-block:: html

  <span>
    <input type="checkbox" value="01" id="authorities1" name="authorities">
    <label for="authorities1">STAFF_MANAGEMENT</label>
  </span>
  <span>
    <input type="checkbox" value="02" id="authorities2" name="authorities">
    <label for="authorities2">MASTER_MANAGEMENT</label>
  </span>
  <span>
    <input type="checkbox" value="03" id="authorities3" name="authorities">
    <label for="authorities3">STOCK_MANAGEMENT</label>
  </span>
  <span>
    <input type="checkbox" value="04" id="authorities4" name="authorities">
    <label for="authorities4">ORDER_MANAGEMENT</label>
  </span>
  <span>
    <input type="checkbox" value="05" id="authorities5" name="authorities">
    <label for="authorities5">SHOW_SHOPPING_CENTER</label>
  </span>

**出力画面**

.. figure:: ./images/codelist_checkbox.png
   :alt: codelist checkbox
   :width: 50%

|

Javaクラスでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

Javaクラスでコードリストを使用する方法については、 :ref:`Javaクラスでのコードリスト使用<serverSide>` を参照されたい。

|

.. _codelist-enum:

EnumCodeListの使用方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
\ ``org.terasoluna.gfw.common.codelist.EnumCodeList``\ は、
\ ``Enum``\ クラスに定義した定数からコードリストを作成するクラスである。

.. note::

    以下の条件に一致するアプリケーションでコードリストを扱う場合は、
    \ ``EnumCodeList``\ を使用して、コードリストのラベルを\ ``Enum``\ クラスで管理することを検討してほしい。
    コードリストのラベルを\ ``Enum``\ クラスで管理することで、
    コード値に紐づく情報と操作を\ ``Enum``\ クラスに集約する事ができる。

    * コード値を\ ``Enum``\ クラスで管理する必要がある(つまり、Javaのロジックでコード値を意識した処理を行う必要がある)
    * UIの国際化(多言語化)の必要がない

|

以下に、\ ``EnumCodeList``\ の使用イメージを示す。

.. figure:: ./images/codelist-enum.png
   :alt: codelist enum
   :width: 100%

.. note::

    \ ``EnumCodeList``\ では、\ ``Enum``\ クラスからコードリストを作成するために必要な情報(コード値とラベル)を取得するためのインタフェースとして、
    \ ``org.terasoluna.gfw.common.codelist.EnumCodeList.CodeListItem``\ インタフェースを提供している。

    \ ``EnumCodeList``\を使用する場合は、作成する\ ``Enum``\ クラスで\ ``EnumCodeList.CodeListItem``\ インタフェースを実装する必要がある。

|

コードリスト設定例
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

**Enumクラスの作成**

\ ``EnumCodeList``\ を使用する場合は、
\ ``EnumCodeList.CodeListItem``\ インタフェースを実装した\ ``Enum``\ クラスを作成する。
以下に作成例を示す。

.. code-block:: java

    package com.example.domain.model;

    import org.terasoluna.gfw.common.codelist.EnumCodeList;

    public enum OrderStatus
        // (1)
        implements EnumCodeList.CodeListItem {

        // (2)
        RECEIVED  ("1", "Received"),
        SENT      ("2", "Sent"),
        CANCELLED ("3","Cancelled");

        // (3)
        private final String value;
        private final String label;

        // (4)
        private OrderStatus(String codeValue, String codeLabel) {
            this.value = codeValue;
            this.label = codeLabel;
        }

        // (5)
        @Override
        public String getCodeValue() {
            return value;
        }

        // (6)
        @Override
        public String getCodeLabel() {
            return label;
        }

    }

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 10 90

    * - 項番
      - 説明
    * - | (1)
      - コードリストとして使用する\ ``Enum``\ クラスでは、
        共通ライブラリから提供している\ ``org.terasoluna.gfw.common.codelist.EnumCodeList.CodeListItem``\ インタフェースを実装する。

        \ ``EnumCodeList.CodeListItem``\ インタフェースには、コードリストを作成するために必要な情報(コード値とラベル)を取得するためのメソッドとして、

        * コード値を取得する\ ``getCodeValue``\ メソッド
        * ラベルを取得する\ ``getCodeLabel``\ メソッド

        が定義されている。
    * - | (2)
      - 定数を定義する。

        定数を生成する際に、コードリストを作成するために必要な情報(コード値とラベル)を指定する。

        上記例では、以下の3つの定数を定義している。

        * \ ``RECEIVED``\ (コード値="\ ``1``\" , ラベル=\ ``Received``\ )
        * \ ``SENT``\  (コード値="\ ``2``\" , ラベル=\ ``Sent``\ )
        * \ ``CANCELLED``\  (コード値="\ ``3``\" , ラベル=\ ``Cancelled``\ )

        .. note::

            \ ``EnumCodeList``\ を使用した際のコードリストの並び順は、定数の定義順となる。

    * - | (3)
      - コードリストを作成するために必要な情報(コード値とラベル)を保持するプロパティを用意する。
    * - | (4)
      - コードリストを作成するために必要な情報(コード値とラベル)を受け取るコンストラクタを用意する。
    * - | (5)
      - 定数が保持するコード値を返却する。

        このメソッドは、\ ``EnumCodeList.CodeListItem``\ インタフェースで定義されているメソッドであり、
        \ ``EnumCodeList``\ が定数からコード値を取得する際に呼び出す。
    * - | (6)
      - 定数が保持するラベルを返却する。

        このメソッドは、\ ``EnumCodeList.CodeListItem``\ インタフェースで定義されているメソッドであり、
        \ ``EnumCodeList``\ が定数からラベルを取得する際に呼び出す。

|

**bean定義ファイル(xxx-codelist.xml)の定義**

コードリスト用のbean定義ファイルに、\ ``EnumCodeList``\を定義する。
以下に定義例を示す。

.. code-block:: xml

    <bean id="CL_ORDERSTATUS"
          class="org.terasoluna.gfw.common.codelist.EnumCodeList"> <!-- (7) -->
        <constructor-arg value="com.example.domain.model.OrderStatus" /> <!-- (8) -->
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 10 90

    * - 項番
      - 説明
    * - | (7)
      - コードリストの実装クラスとして、\ ``EnumCodeList``\ クラスを指定する。
    * - | (8)
      - \ ``EnumCodeList``\ クラスのコンストラクタに、\ ``EnumCodeList.CodeListItem``\ インタフェースを実装した\ ``Enum``\ クラスのFQCNを指定する。

|

テンプレートHTMLでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

テンプレートHTMLでコードリストを使用する方法については、前述した :ref:`clientSide` を参照されたい。

|

Javaクラスでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

Javaクラスでコードリストを使用する方法については、
前述した :ref:`serverSide` を参照されたい。

|

.. _codelisti18n:

I18nCodeListの使用方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``org.terasoluna.gfw.common.codelist.i18n.I18nCodeList`` は、国際化に対応しているコードリストである。
ロケール毎にコードリストを設定することで、ロケールに対応したコードリストを返却できる。

``I18nCodeList`` の実装クラスとして、 ``org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList`` および ``org.terasoluna.gfw.common.codelist.i18n.SimpleReloadableI18nCodeList`` を提供している。

**I18nCodeList(SimpleI18nCodeList)のイメージ**

.. figure:: ./images/codelist-i18n.png
   :alt: codelist i18n
   :width: 100%

|

コードリスト設定例
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

``I18nCodeList``\ は行が\ ``Locale``\ 、列がコード値、セルの内容がラベルである2次元のテーブルをイメージすると理解しやすい。

料金を選択するセレクトボックスの場合を例に挙げると以下のようなテーブルができる。

.. tabularcolumns:: |p{0.10\linewidth}|p{0.15\linewidth}|p{0.14\linewidth}|p{0.14\linewidth}|p{0.14\linewidth}|p{0.14\linewidth}|p{0.14\linewidth}|
.. list-table::
   :header-rows: 1
   :stub-columns: 1
   :widths: 10 15 15 15 15 15 15

   * - row=Locale,column=Code
     - 0
     - 10000
     - 20000
     - 30000
     - 40000
     - 50000
   * - en
     - unlimited
     - Less than \\10,000
     - Less than \\20,000
     - Less than \\30,000
     - Less than \\40,000
     - Less than \\50,000
   * - ja
     - 上限なし
     - 10,000円以下
     - 20,000円以下
     - 30,000円以下
     - 40,000円以下
     - 50,000円以下



この国際化対応コードリストのテーブルを構築するために\ ``SimpleI18nCodeList``\ は3つの設定方法を用意している。

* 行単位でLocale毎の\ ``CodeList``\ を設定する
* 行単位でLocale毎の\ ``java.util.Map``\ (key=コード値, value=ラベル)を設定する
* 列単位でコード値毎の\ ``java.util.Map``\ (key=Locale, value=ラベル)を設定する

基本的には、**「行単位でLocale毎のCodeListを設定する」方法でコードリストを設定することを推奨する。**

\ ``SimpleReloadableI18nCodeList``\ は更新可能なコードリストを行に持つ以下の設定方法を用意している。

* 行単位でLocale毎の \ ``ReloadableCodeList``\ ( \ ``JdbcCodeList``\ )を設定する

.. note::

    terasoluna-gfw-common 5.4.2.RELEASEからリロードに対応した ``SimpleReloadableI18nCodeList`` が追加された。
    更新可能なコードリストを行に持つ ``SimpleI18nCodeList`` を利用している場合は、 ``SimpleReloadableI18nCodeList`` に置き換えることを推奨する。

上記例の料金を選択するセレクトボックスの場合を行単位でLocale毎の\ ``CodeList``\ を設定する方法について説明する。
他の設定方法については  :ref:`afterCodelisti18n` 参照されたい。

|

**Bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml
  
    <bean id="CL_I18N_PRICE"
        class="org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList">
        <property name="rowsByCodeList"> <!-- (1) -->
            <util:map>
                <entry key="en" value-ref="CL_PRICE_EN" />
                <entry key="ja" value-ref="CL_PRICE_JA" />
            </util:map>
        </property>
    </bean>
  
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 10 90
  
    * - 項番
      - 説明
    * - | (1)
      - | rowsByCodeListプロパティにkeyが\ ``java.lang.Locale``\ のMapを設定する。
        | Mapには、keyにロケール、value-refにロケールに対応したコードリストクラスの参照先を指定する。
        | Mapのvalueは各ロケールに対応したコードリストクラスを参照する。

|

**Locale毎にSimpleMapCodeListを用意する場合のBean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml
  
    <bean id="CL_I18N_PRICE"
        class="org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList">
        <property name="rowsByCodeList">
            <util:map>
                <entry key="en" value-ref="CL_PRICE_EN" />
                <entry key="ja" value-ref="CL_PRICE_JA" />
            </util:map>
        </property>
    </bean>
  
    <bean id="CL_PRICE_EN" class="org.terasoluna.gfw.common.codelist.SimpleMapCodeList">  <!-- (2) -->
        <property name="map">
            <util:map>
                <entry key="0" value="unlimited" />
                <entry key="10000" value="Less than \\10,000" />
                <entry key="20000" value="Less than \\20,000" />
                <entry key="30000" value="Less than \\30,000" />
                <entry key="40000" value="Less than \\40,000" />
                <entry key="50000" value="Less than \\50,000" />
            </util:map>
        </property>
    </bean>
  
    <bean id="CL_PRICE_JA" class="org.terasoluna.gfw.common.codelist.SimpleMapCodeList">  <!-- (3) -->
        <property name="map">
            <util:map>
                <entry key="0" value="上限なし" />
                <entry key="10000" value="10,000円以下" />
                <entry key="20000" value="20,000円以下" />
                <entry key="30000" value="30,000円以下" />
                <entry key="40000" value="40,000円以下" />
                <entry key="50000" value="50,000円以下" />
            </util:map>
        </property>
    </bean>
  
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 10 90
  
    * - 項番
      - 説明
    * - | (2)
      - | ロケールが"en"であるbean定義 ``CL_PRICE_EN`` について、コードリストクラスを ``SimpleMapCodeList`` で設定している。
    * - | (3)
      - | ロケールが"ja"であるbean定義 ``CL_PRICE_JA`` について、コードリストクラスを ``SimpleMapCodeList`` で設定している。

|

**Locale毎にJdbcCodeListを用意する場合のBean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml
  
    <bean id="CL_I18N_PRICE"
        class="org.terasoluna.gfw.common.codelist.i18n.SimpleReloadableI18nCodeList">  <!-- (4) -->
        <property name="rowsByCodeList">
            <util:map>
                <entry key="en" value-ref="CL_PRICE_EN" />
                <entry key="ja" value-ref="CL_PRICE_JA" />
            </util:map>
        </property>
    </bean>
  
    <bean id="CL_PRICE_EN" parent="AbstractJdbcCodeList">  <!-- (5) -->
        <property name="querySql"
            value="SELECT code, label FROM price WHERE locale = 'en' ORDER BY code" />
        <property name="valueColumn" value="code" />
        <property name="labelColumn" value="label" />
    </bean>
  
    <bean id="CL_PRICE_JA" parent="AbstractJdbcCodeList">  <!-- (6) -->
        <property name="querySql"
            value="SELECT code, label FROM price WHERE locale = 'ja' ORDER BY code" />
        <property name="valueColumn" value="code" />
        <property name="labelColumn" value="label" />
    </bean>
  
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 10 90
  
    * - 項番
      - 説明
    * - | (4)
      - | 更新可能なコードリストを行に持つ場合は、``SimpleReloadableI18nCodeList`` を利用する。
    * - | (5)
      - | ロケールが"en"であるbean定義 ``CL_PRICE_EN`` について、コードリストクラスを ``JdbcCodeList`` で設定している。
    * - | (6)
      - | ロケールが"ja"であるbean定義 ``CL_PRICE_JA`` について、コードリストクラスを ``JdbcCodeList`` で設定している。
  

テーブル定義(priceテーブル)には以下のデータを投入する。

.. tabularcolumns:: |p{0.20\linewidth}|p{0.20\linewidth}|p{0.60\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 20 20 60
    :class: longtable
  
    * - locale
      - code
      - label
    * - | en
      - | 0
      - | unlimited
    * - | en
      - | 10000
      - | Less than \\10,000
    * - | en
      - | 20000
      - | Less than \\20,000
    * - | en
      - | 30000
      - | Less than \\30,000
    * - | en
      - | 40000
      - | Less than \\40,000
    * - | en
      - | 50000
      - | Less than \\50,000
    * - | ja
      - | 0
      - | 上限なし
    * - | ja
      - | 10000
      - | 10,000円以下
    * - | ja
      - | 20000
      - | 20,000円以下
    * - | ja
      - | 30000
      - | 30,000円以下
    * - | ja
      - | 40000
      - | 40,000円以下
    * - | ja
      - | 50000
      - | 50,000円以下

.. raw:: latex

   \newpage

|

I18nCodeListにおけるロケール解決
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

\ ``I18nCodeList``\は要求されたロケールがコードリストに定義されていない場合、以下の順序でロケールの解決を行う。

#. 国と言語を組み合わせたロケール(例:ja_JP)がコードリストに定義されていない場合、対応する言語のみのロケール(例:ja)を使用する。
#. 言語のみのロケールがコードリストに定義されていない場合、デフォルトのロケールを使用する。

デフォルトのロケールは以下の順序で決定する。

#. ``fallbackTo`` プロパティが指定されている場合は、指定されたロケールを使用する。
#. ``fallbackTo`` プロパティが指定されていない場合は、JVMインスタンスの\ `デフォルトロケール <https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#getDefault-->`_ \、もしくは対応する言語のみのロケールを使用する。

.. warning::

    デフォルトのロケールに対応するコードリストが定義されていなかった場合、Bean生成時にエラーとなりアプリケーションの起動に失敗する。

    このため、様々な環境でアプリケーションを運用する場合や、デフォルトとしたいロケールとJVMインスタンスのデフォルトロケールが異なる場合は、``fallbackTo`` プロパティを指定することを強く推奨する。

|


``fallbackTo`` プロパティの設定例を以下に示す。

**fallbackToプロパティの設定**

.. code-block:: xml
  
    <bean id="CL_I18N_PRICE"
        class="org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList">
        <property name="rowsByCodeList">
            <util:map>
                <entry key="en" value-ref="CL_PRICE_EN" />
                <entry key="ja" value-ref="CL_PRICE_JA" />
            </util:map>
        </property>
        <property name="fallbackTo" value="en" />  <!-- (1) -->
    </bean>
  
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 10 90
  
    * - 項番
      - 説明
    * - | (1)
      - | \ ``fallbackTo``\プロパティにロケール"en"を設定する。
        | これにより、要求されたロケールの言語ロケールが"en"、"ja"以外の場合、ロケール"en"が使用される。

|

.. _codelisti18n_failBackTo:

テンプレートHTMLでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

テンプレートHTMLの基本的な実装は :ref:`テンプレートHTMLでのコードリスト使用<clientSide>` と同様のため、説明は省略する。

ここでは、 リクエストのロケールがコードリスト定義されていなかった場合に対応するため、インターセプターでリクエスト属性に ``SimpleI18nCodeList`` を設定し、テンプレートHTMLに渡す方法を紹介する。

**テンプレートHTML実装例**

.. code-block:: html

  <select th:field="*{basePrice}">
      <option th:each="price : ${CL_I18N_PRICE}" th:value="${price.key}" th:text="${price.value}"></option>
  </select>

**出力HTML lang=en**

.. code-block:: html

  <select id="basePrice" name="basePrice">
    <option value="0">unlimited</option>
    <option value="1">Less than \\10,000</option>
    <option value="2">Less than \\20,000</option>
    <option value="3">Less than \\30,000</option>
    <option value="4">Less than \\40,000</option>
    <option value="5">Less than \\50,000</option>
  </select>

**出力HTML lang=ja**

.. code-block:: html

  <select id="basePrice" name="basePrice">
    <option value="0">上限なし</option>
    <option value="1">10,000円以下</option>
    <option value="2">20,000円以下</option>
    <option value="3">30,000円以下</option>
    <option value="4">40,000円以下</option>
    <option value="5">50,000円以下</option>
  </select>

**出力画面 lang=en**

.. figure:: ./images/codelist_i18n_en.png
   :alt: codelist i18n en
   :width: 20%

**出力画面 lang=ja**

.. figure:: ./images/codelist_i18n_ja.png
   :alt: codelist i18n ja
   :width: 20%

|

.. _codelist-i18nCodeLst-java-implement:

Javaクラスでのコードリスト使用
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

\ ``I18nCodeList``\からコードリストを取得するには、以下のいずれかのメソッドを使用する。

- `asMap()` メソッド
    ``org.springframework.context.i18n.LocaleContextHolder`` を利用して適切なロケールのコードリストを取得する。``LocaleContextHolder`` は ``org.springframework.web.servlet.LocaleResolver`` を利用してクライアントから指定されたロケールを取得する。
- `asMap(Locale)` メソッド
    指定されたロケールのコードリストを取得する。

.. note::

    ``LocaleResolver``\ の設定方法については、\ :doc:`../WebApplicationDetail/Internationalization`\ を参照されたい。

    ``LocaleResolver``\の ``defaultLocale`` プロパティを指定している場合は、コードリストの\ ``fallbackTo``\プロパティに同じロケールを指定することで、 ``LocaleResolver`` で意図したロケールのコードリストを使用させることができる。

|

``asMap()`` メソッドを利用する場合、前述した :ref:`serverSide` と同様の方法で実装を行うことができる。

.. code-block:: java

  import javax.inject.Named;

  import org.terasoluna.gfw.common.codelist.CodeList;

  @Service
  public class OrderServiceImpl implements OrderService {

      @Inject
      @Named("CL_ORDERSTATUS")
      I18nCodeList orderStatusCodeList;

      public boolean existOrderStatus(String target) {
          return orderStatusCodeList.asMap().containsKey(target); // (1)
      }
  }

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | ``I18nCodeList#asMap()`` メソッドでコードリストを ``java.util.Map`` 形式で取得する。

|

業務要件によって、特定のロケールのコードリストを取得する必要がある場合は\ ``asMap(Locale)``\メソッドを使用する

.. code-block:: java

  import java.util.Locale;
  import javax.inject.Named;

  import org.terasoluna.gfw.common.codelist.CodeList;

  @Service
  public class OrderServiceImpl implements OrderService {

      @Inject
      @Named("CL_ORDERSTATUS")
      I18nCodeList orderStatusCodeList;

      public boolean existOrderStatus(String target) {
          return orderStatusCodeList.asMap(Locale.ENGLISH).containsKey(target); // (1)
      }
  }

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | ``I18nCodeList#asMap(Locale)`` メソッドで、指定したロケールのコードリストを ``java.util.Map`` 形式で取得する。
       | ここでは \ ``Locale.ENGLISH``\("en")を指定している。

|

.. _codelist-display-label:

特定のコード値からコード名を表示する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

テンプレートHTMLからコードリストを参照する場合は、 ``CodeListInterceptor`` がリクエスト属性にコードリストを  ``java.util.Map`` で格納しているため、``Map`` インターフェースと同じ方法で参照することができる。

コードリストを用いて特定のコード値からコード名を表示する方法について、以下に実装例を示す。

**テンプレートHTML実装例**

.. code-block:: html

    <span th:text="${orderForm.orderStatus} != null ? |Order Status : ${CL_ORDERSTATUS.get(orderForm.orderStatus)}|"></span> <!--/* (1) */-->

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - コードリストを定義したbeanID(この例では ``CL_ORDERSTATUS`` ) を属性名として、コードリスト( ``java.util.Map`` インタフェース)を取得する。
       取得した ``Map`` インタフェースのキーとしてコード値(この例では ``orderStatus`` に格納された値) を指定することで、対応するコード名を表示することができる。
       キーとして利用する変数値は必ず\ ``null``\ チェックを行うことを推奨する。詳細は、\ :doc:`../WebApplicationDetail/Thymeleaf`\ の\ :ref:`SpEL評価時におけるnull-safetyの影響について <ThymeleafOverviewNullSafetyAtSpEL>`\ を参照されたい。

|

.. _codelist-validate:

コードリストを用いたコード値の入力チェック
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

入力値がコードリスト内に定義されたコード値であるかどうかチェックするような場合、
共通ライブラリでは、BeanValidation用のアノテーション、 ``org.terasoluna.gfw.common.codelist.ExistInCodeList`` を提供している。

BeanValidationや、メッセージ出力方法の詳細については、 :doc:`../WebApplicationDetail/Validation` を参照されたい。

|

@ExistInCodeList の設定例
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

コードリストを用いた入力チェック方法について、以下に実装例を示す。

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_GENDER" class="org.terasoluna.gfw.common.codelist.SimpleMapCodeList">
        <property name="map">
            <map>
                <entry key="M" value="Male" />
                <entry key="F" value="Female" />
            </map>
        </property>
    </bean>

**Formオブジェクト**

.. code-block:: java

    public class Person {
        @ExistInCodeList(codeListId = "CL_GENDER")  // (1)
        private String gender;

        // getter and setter omitted
    }

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | 入力チェックを行いたいフィールドに対して、 ``@ExistInCodeList`` アノテーションを設定し、
       | codeListIdにチェック元となる、コードリストを指定する。

上記の結果、 ``gender`` にM、F以外の文字が格納されている場合、エラーになる。

.. note::

    terasoluna-gfw-common 5.4.2.RELEASEから、``@ExistInCodeList`` の入力チェックの対象として、 \ ``CharSequence``\ インタフェースの実装クラス(\ ``String``\ など) または \ ``Character``\ に加え、
    \ ``Number``\ 継承クラス(\ ``Integer``\ など)をサポートするよう変更された。

    \ ``NumberRangeCodeList``\ の \ ``valueFormat``\ プロパティを指定している場合、 \ ``Number``\ 型フィールドの値を当該プロパティを利用してフォーマットした値がコードリストに存在することをチェックする。


|


How to extend
--------------------------------------------------------------------------------

.. _codeListTaskScheduler:

コードリストをリロードする場合
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

前述した共通ライブラリで提供しているコードリストは、アプリケーション起動時に読み込まれ、それ以降は、基本的に更新されない。
しかし、コードリストのマスタデータを更新した時、コードリストも更新したい場合がある。

例:JdbcCodeListを使用して、DBのマスタを変更した時にコードリストの更新を行う場合。

共通ライブラリでは、コードリストを更新可能とするインタフェースを提供している。

#. ``org.terasoluna.gfw.common.codelist.ReloadableCodeList`` :コードリストを更新する
#. ``org.terasoluna.gfw.common.codelist.i18n.ReloadableI18nCodeList`` :行に持つコードリストを含むコードリストを更新する

コードリストの更新方法としては、以下2点の方法がある。

#. Task Schedulerで実現する方法
#. Controller(Service)クラスでrefreshメソッドを呼び出す方法

本ガイドラインでは、\ `Springから提供されているTask Scheduler <https://docs.spring.io/spring/docs/5.2.20.RELEASE/spring-framework-reference/integration.html#scheduling>`_\ を使用して、コードリストを定期的にリロードする方式を基本的に推奨する。

ただし、任意のタイミングでコードリストをリフレッシュする必要がある場合はControllerクラスでrefreshメソッドを呼び出す方法で実現すればよい。

.. note::

    ``ReloadableCodeList`` および ``ReloadableI18nCodeList`` インターフェースを実装しているコードリストについては、 :ref:`コードリスト種類一覧<listOfCodeList>` を参照されたい。

|

Task Schedulerで実現する方法
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

Task Schedulerの設定例について、以下に示す。

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <task:scheduler id="taskScheduler" pool-size="10"/>  <!-- (1) -->

    <task:scheduled-tasks scheduler="taskScheduler">  <!-- (2) -->
        <task:scheduled ref="CL_AUTHORITIES" method="refresh" cron="${cron.codelist.refreshTime}"/>  <!-- (3) -->
    </task:scheduled-tasks>

    <bean id="CL_AUTHORITIES" parent="AbstractJdbcCodeList">
        <property name="querySql"
            value="SELECT authority_id, authority_name FROM authority ORDER BY authority_id" />
        <property name="valueColumn" value="authority_id" />
        <property name="labelColumn" value="authority_name" />
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | ``<task:scheduler>`` の要素を定義する。pool-size属性にスレッドのプールサイズを指定する。
       | pool-size属性を指定しない場合、"1" が設定される。
   * - | (2)
     - | ``<task:scheduled-tasks>`` の要素を定義し、scheduler属性に、 ``<task:scheduler>`` のIDを設定する。
   * - | (3)
     - | ``<task:scheduled>`` 要素を定義する。method属性に、refreshメソッドを指定する。
       | cron属性に、``org.springframework.scheduling.support.CronSequenceGenerator`` でサポートされた形式で記述すること。
       | cron属性は開発環境、商用環境など環境によってリロードするタイミングが変わることが想定されるため、プロパティファイルや、環境変数等から取得することを推奨する。
       |
       | **cron属性の設定例**
       | 「秒 分 時 月 年 曜日」で指定する。
       | 毎秒実行               「\* \* \* \* \* \*」
       | 毎時実行               「0 0 \* \* \* \*」
       | 平日の9-17時の毎時実行 「0 0 9-17 \* \* MON-FRI」
       |
       | 詳細はJavaDocを参照されたい。
       | https://docs.spring.io/spring/docs/5.2.20.RELEASE/javadoc-api/org/springframework/scheduling/support/CronSequenceGenerator.html

|

Controller(Service)クラスでrefreshメソッドを呼び出す方法
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

refreshメソッドを直接呼び出す場合について、
JdbcCodeListのrefreshメソッドをServiceクラスで呼び出す場合の実装例を、以下に示す。

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_AUTHORITIES" parent="AbstractJdbcCodeList">
        <property name="querySql"
            value="SELECT authority_id, authority_name FROM authority ORDER BY authority_id" />
        <property name="valueColumn" value="authority_id" />
        <property name="labelColumn" value="authority_name" />
    </bean>

**Controllerクラス**

.. code-block:: java

    @Controller
    @RequestMapping(value = "codelist")
    public class CodeListController {

        @Inject
        CodeListService codeListService; // (1)

        @RequestMapping(method = RequestMethod.GET, params = "refresh")
        public String refreshJdbcCodeList() {
            codeListService.refresh(); // (2)
            return "codelist/jdbcCodeList";
        }
    }

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | ReloadableCodeListクラスのrefreshメソッドを実行するServiceクラスをインジェクションする。
   * - | (2)
     - | ReloadableCodeListクラスのrefreshメソッドを実行するServiceクラスのrefreshメソッドを実行する。

**Serviceクラス**

以下は実装クラスのみ記述し、インターフェースクラスは省略。

.. code-block:: java

    @Service
    public class CodeListServiceImpl implements CodeListService { // (3)

        @Inject
        @Named(value = "CL_AUTHORITIES") // (4)
        ReloadableCodeList codeListItem; // (5)

        @Override
        public void refresh() { // (6)
            codeListItem.refresh(); // (7)
        }
    }


.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90


   * - 項番
     - 説明
   * - | (3)
     - | 実装クラス ``CodeListServiceImpl`` は、インターフェース ``CodeListService`` を実装する。
   * - | (4)
     - | コードリストをインジェクションするとき、 ``@Named`` で、該当するコードリストを指定する。
       | value属性に取得したいbeanのIDを指定すること。
       | Bean定義ファイルに定義されているbeanタグのID属性"CL_AUTHORITIES"のコードリストがインジェクションされる。
   * - | (5)
     - | フィールドの型にReloadableCodeListインターフェースを定義すること。
       | (4)で指定したBeanはReloadableCodeListインターフェースを実装していること。
   * - | (6)
     - | Serviceクラスで定義したrefreshメソッド。
       | Controllerクラスから呼び出されている。
   * - | (7)
     - | ReloadableCodeListインターフェースを実装したコードリストのrefreshメソッド。
       | refreshメソッドを実行することで、コードリストが更新される。

.. note::

    terasoluna-gfw-common 5.4.2.RELEASEで追加された ``SimpleReloadableI18nCodeList`` では、refreshメソッドで行に持つすべてのReloadableCodeListを更新することが可能である。

    アプリケーションの実装によっては、行に持つReloadableCodeListが更新されている前提で ``SimpleReloadableI18nCodeList`` のみ更新すれば良い場合もあり得る。
    この場合は、``ReloadableI18nCodeList#refresh(boolean)`` メソッドの引数に ``false`` をセットして実行すれば良い。


|

.. _originalCustomizeCodeList:

コードリストを独自カスタマイズする方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

共通ライブラリで提供している4種類のコードリストで実現できないコードリストを作成したい場合、コードリストを独自にカスタマイズすることができる。
独自カスタマイズする場合、作成できるコードリストの種類と実装方法について、以下の表に示す。

.. tabularcolumns:: |p{0.10\linewidth}|p{0.15\linewidth}|p{0.30\linewidth}|p{0.45\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 15 30 45

   * - 項番
     - Reloadable
     - 継承するクラス
     - 実装箇所
   * - | (1)
     - | 不要
     - | ``org.terasoluna.gfw.common.codelist.AbstractCodeList``
     - | ``asMap`` をオーバライド
   * - | (2)
     - | 必要
     - | ``org.terasoluna.gfw.common.codelist.AbstractReloadableCodeList``
     - | ``retrieveMap`` をオーバライド

``org.terasoluna.gfw.common.codelist.CodeList`` 、 ``org.terasoluna.gfw.common.codelist.ReloadableCodeList`` インターフェースを直接実装しても実現はできるが、共通ライブラリで提供されている抽象クラスを拡張することで、最低限の実装で済む。

以下に、独自カスタマイズの実例について示す。
例として、今年と来年の年のリストを作るコードリストについて説明する。
(例:今年が2013の場合、コードリストには、"2013、2014"の順で格納される。)

**コードリストクラス**

.. code-block:: java


    package com.example.sample.domain.codelist;

    ...

    public class DepYearCodeList extends AbstractCodeList { // (1)

        private JodaTimeDateFactory dateFactory;

        public void setDateFactory(JodaTimeDateFactory dateFactory) { //(2)
            this.dateFactory = dateFactory;
        }

        @Override
        public Map<String, String> asMap() {  // (3)
            DateTime dateTime = dateFactory.newDateTime();
            DateTime nextYearDateTime = dateTime.plusYears(1);

            Map<String, String> depYearMap = new LinkedHashMap<String, String>();

            String thisYear = dateTime.toString("Y");
            String nextYear = nextYearDateTime.toString("Y");
            depYearMap.put(thisYear, thisYear);
            depYearMap.put(nextYear, nextYear);

            return Collections.unmodifiableMap(depYearMap);
        }
    }

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90


   * - 項番
     - 説明
   * - | (1)
     - | ``AbstractCodeList`` を継承する。
       | 今年と来年の年のリストを作る時、動的にシステム日付から算出して作成しているため、リロードは不要。
   * - | (2)
     - | システム日付のDateクラスを作成する ``org.terasoluna.gfw.common.date.jodatime.JodaTimeDateFactory`` をインジェクションするためのセッターを用意する。
       | ``JodaTimeDateFactory`` を利用して今年と来年の年を取得することができる。
   * - | (3)
     - | ``asMap`` メソッドをオーバライドして、今年と来年の年のリストを作成する。
       | 作成したいコードリスト毎に実装が異なる。

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_YEAR" class="com.example.sample.domain.codelist.DepYearCodeList"> <!-- (1) -->
        <property name="dateFactory" ref="dateFactory" /> <!-- (2) -->
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90


   * - 項番
     - 説明
   * - | (1)
     - | 作成したコードリストクラスをbean定義する。
       | id に ``CL_YEAR`` を指定することで、bean定義で設定した ``CodeListInterceptor`` によりコードリストをコンポーネント登録する。
   * - | (2)
     - | システム日付のDateクラスを作成する ``JodaTimeDateFactory`` を設定する。
       | 事前に、bean定義ファイルにDataFactory実装クラスを設定する必要がある。

|

**テンプレートHTML実装例**

.. code-block:: html

  <select th:field="*{mostRecentYear}">
      <option th:each="recentYear : ${CL_YEAR}" th:value="${recentYear.key}" th:text="${recentYear.value}"></option> <!--/* (1) */-->
  </select>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | コンポーネント登録した ``CL_YEAR`` を 変数式 ``${}`` で指定することで、該当のコードリストを取得することができる。

**出力HTML**

.. code-block:: html

  <select id="mostRecentYear" name="mostRecentYear">
     <option value="2013">2013</option>
     <option value="2014">2014</option>
  </select>

**出力画面**

.. figure:: ./images/codelist_customizeCodelist.png
   :alt: customized codelist
   :width: 10%

.. note::

    リロード可能であるCodeListを独自カスタマイズする場合、スレッドセーフになるように実装すること。

|

Appendix
--------------------------------------------------------------------------------

.. _afterCodelisti18n:

SimpleI18nCodeListのコードリスト設定方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

SimpleI18nCodeListのコードリスト設定について、 :ref:`codelisti18n` で設定されているコードリスト設定の他に2つ設定方法がある。
料金を選択するセレクトボックスの場合の例を用いて、それぞれの設定方法を説明する。

行単位でLocale毎の\ ``java.util.Map``\ (key=コード値, value=ラベル)を設定する
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_I18N_PRICE"
        class="org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList">
        <property name="rows"> <!-- (1) -->
            <util:map>
                <entry key="en">
                    <util:map>
                        <entry key="0" value="unlimited" />
                        <entry key="10000" value="Less than \\10,000" />
                        <entry key="20000" value="Less than \\20,000" />
                        <entry key="30000" value="Less than \\30,000" />
                        <entry key="40000" value="Less than \\40,000" />
                        <entry key="50000" value="Less than \\50,000" />
                    </util:map>
                </entry>
                <entry key="ja">
                    <util:map>
                        <entry key="0" value="上限なし" />
                        <entry key="10000" value="10,000円以下" />
                        <entry key="20000" value="20,000円以下" />
                        <entry key="30000" value="30,000円以下" />
                        <entry key="40000" value="40,000円以下" />
                        <entry key="50000" value="50,000円以下" />
                    </util:map>
                </entry>
            </util:map>
        </property>
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | rowsプロパティに対して、"MapのMap"を設定する。外側のMapのkeyは\ ``java.lang.Locale``\ である。
       | 内側のMapのkeyはコード値、valueはロケールに対応したラベルである。

|

列単位でコード値毎の\ ``java.util.Map``\ (key=Locale, value=ラベル)を設定する
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_I18N_PRICE"
        class="org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList">
        <property name="columns"> <!-- (1) -->
            <util:map>
                <entry key="0">
                    <util:map>
                        <entry key="en" value="unlimited" />
                        <entry key="ja" value="上限なし" />
                    </util:map>
                </entry>
                <entry key="10000">
                    <util:map>
                        <entry key="en" value="Less than \\10,000" />
                        <entry key="ja" value="10,000円以下" />
                    </util:map>
                </entry>
                <entry key="20000">
                    <util:map>
                        <entry key="en" value="Less than \\20,000" />
                        <entry key="ja" value="20,000円以下" />
                    </util:map>
                </entry>
                <entry key="30000">
                    <util:map>
                        <entry key="en" value="Less than \\30,000" />
                        <entry key="ja" value="30,000円以下" />
                    </util:map>
                </entry>
                <entry key="40000">
                    <util:map>
                        <entry key="en" value="Less than \\40,000" />
                        <entry key="ja" value="40,000円以下" />
                    </util:map>
                </entry>
                <entry key="50000">
                    <util:map>
                        <entry key="en" value="Less than \\50,000" />
                        <entry key="ja" value="50,000円以下" />
                    </util:map>
                </entry>
            </util:map>
        </property>
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | columnsプロパティに対して、"MapのMap"を設定する。外側のMapのkeyはコード値である。
       | 内側のMapのkeyは\ ``java.lang.Locale``\、valueはロケールに対応したラベルである。

|

.. _CodeListAppendixNumberRangeCodeListVariation:

NumberRangeCodeListのバリエーション
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

降順のNumberRangeCodeListの作成
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

次に、Toの値をFromの値より小さくする(To < From)場合の実装例を、以下に示す。

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_BIRTH_YEAR"
        class="org.terasoluna.gfw.common.codelist.NumberRangeCodeList">
        <property name="from" value="2013" /> <!-- (1) -->
        <property name="to" value="2000" /> <!-- (2) -->
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 10 90

    * - 項番
      - 説明
    * - | (1)
      - | 範囲開始の値を指定する。name属性"to"のvalue属性の値より大きい値を指定する。
        | この指定によって、interval分減少した値を、To~Fromの範囲分のリストとして、降順に表示する。
        | intervalは設定していないため、デフォルトの値1が適用される。
    * - | (2)
      - | 範囲終了の値を設定する。
        | 本例では、2000を指定することにより、リストには2013~2000までの範囲で1ずつ減少して格納される。

|

**テンプレートHTML実装例**

.. code-block:: html

  <select th:field="*{birthYear}">
    <option th:each="birthYear : ${CL_BIRTH_YEAR}" th:value="${birthYear.key}" th:text="${birthYear.value}"></option>
  </select>

**出力HTML**

.. code-block:: html

  <select id="birthYear" name="birthYear">
    <option value="2013">2013</option>
    <option value="2012">2012</option>
    <option value="2011">2011</option>
    <option value="2010">2010</option>
    <option value="2009">2009</option>
    <option value="2008">2008</option>
    <option value="2007">2007</option>
    <option value="2006">2006</option>
    <option value="2005">2005</option>
    <option value="2004">2004</option>
    <option value="2003">2003</option>
    <option value="2002">2002</option>
    <option value="2001">2001</option>
    <option value="2000">2000</option>
  </select>

**出力画面**

.. figure:: ./images/codelist_numberrenge2.png
    :alt: codelist numberrenge2

|

NumberRangeCodeListのインターバルの変更
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

次に、interval値を設定する場合の実装例を、以下に示す。

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_BULK_ORDER_QUANTITY_UNIT"
        class="org.terasoluna.gfw.common.codelist.NumberRangeCodeList">
        <property name="from" value="10" />
        <property name="to" value="50" />
        <property name="interval" value="10" /> <!-- (1) -->
    </bean>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
    :header-rows: 1
    :widths: 10 90

    * - 項番
      - 説明
    * - | (1)
      - | 増加(減少)値を指定する。この指定によって、interval値を増加(減少)した値を、From~Toの範囲内でコードリストとして格納する。
        | 上記の例だと、コードリストには\ ``10``\,\ ``20``\,\ ``30``\,\ ``40``\,\ ``50``\の順で格納される。

|

**テンプレートHTML実装例**

.. code-block:: html

  <select th:field="*{quantity}">
    <option th:each="quantity : ${CL_BULK_ORDER_QUANTITY_UNIT}" th:value="${quantity.key}" th:text="${quantity.value}"></option>
  </select>

**出力HTML**

.. code-block:: html

    <select id="quantity" name="quantity">
        <option value="10">10</option>
        <option value="20">20</option>
        <option value="30">30</option>
        <option value="40">40</option>
        <option value="50">50</option>
    </select>

**出力画面**

.. figure:: ./images/codelist_numberrenge3.png
    :alt: codelist numberrenge3

.. note::

    interval値分増加(減少)した値が、Form~Toの値が範囲を超えた場合は、コードリストに格納されない。

    具体的には、

     .. code-block:: xml

        <bean id="CL_BULK_ORDER_QUANTITY_UNIT"
            class="org.terasoluna.gfw.common.codelist.NumberRangeCodeList">
            <property name="from" value="10" />
            <property name="to" value="55" />
            <property name="interval" value="10" />
        </bean>

    という定義を行った場合、

    コードリストには\ ``10``\,\ ``20``\,\ ``30``\,\ ``40``\,\ ``50``\の計5つが格納される。
    次のintervalである\ ``60``\及び範囲の閾値である\ ``55``\はコードリストに格納されない。


.. raw:: latex

   \newpage

.. _directRefCodeList:

テンプレートHTMLから直接コードリストBeanを参照する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

:ref:`テンプレートHTMLでのコードリスト使用<clientSide>` では、Spring MVCを経由する全てのリクエストに対して、``CodeListIntercepter`` がコードリストのBeanをリクエスト属性として登録するため、コードリストの数が多くなるとリクエスト毎のオーバーヘッドの増加が懸念される。

ここでは、リクエスト毎のオーバーヘッドの増加を防ぐ方法の一つとして、コードリストBeanをテンプレートHTMLから直接参照する方法を紹介する。
ThymeleafではSpEL式を利用して直接Beanを参照することができるが、こちらを利用することでオーバーヘッドの増加を防止することができる。
いずれの方法を利用するかは、プロジェクトの要件によって適切に検討されたい。

.. _codeListDirectRefCodeListSpringMvc:

**bean定義ファイル(spring-mvc.xml)の定義**

.. code-block:: xml
   :emphasize-lines: 2-7

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <bean class="org.terasoluna.gfw.web.codelist.CodeListInterceptor"> <!-- (1) -->
                <property name="codeListIdPattern" value="CL_.+" />
            </bean>
        </mvc:interceptor>
 
    <!-- omitted -->

    </mvc:interceptors>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | ``CodeListInterceptor`` の設定があれば、削除する。


**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_ORDERSTATUS" class="org.terasoluna.gfw.common.codelist.SimpleMapCodeList">
        <property name="map">
            <util:map>
                <entry key="1" value="Received" />
                <entry key="2" value="Sent" />
                <entry key="3" value="Cancelled" />
            </util:map>
        </property>
    </bean>

**テンプレートHTML実装例**

.. code-block:: html
   :emphasize-lines: 2
 
    <select th:field="*{orderStatus}">
        <option th:each="order : ${@CL_ORDERSTATUS.asMap()}" th:value="${order.key}" th:text="${order.value}"></option> <!--/* (1) */-->
    </select>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | 変数式により取得したコードリストBeanのasMapメソッドにより、Map形式で参照することができる。
       | なお、``SimpleI18nCodeList`` の場合は、 ``asMap`` メソッドの引数として ``Locale`` を渡す必要がある。

**出力HTML**

.. code-block:: html

    <select id="orderStatus" name="orderStatus">
        <option value="1">Received</option>
        <option value="2">Sent</option>
        <option value="3">Cancelled</option>
    </select>

|

.. _CodeListAppendixDirectReferenceSimpleI18nCodeList:

SimpleI18nCodeListをテンプレートHTMLから直接参照する方法
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

ここでは、``CodeListInterceptor`` の実装と同様に、リクエストのロケールに対するコードリストに定義されていなかった場合、デフォルトで設定したロケールに対するコードリストを表示する例を紹介する。

**bean定義ファイル(spring-mvc.xml)の定義**

:ref:`bean定義ファイル(spring-mvc.xml)の定義<codeListDirectRefCodeListSpringMvc>` と同様なため割愛する。

**bean定義ファイル(xxx-codelist.xml)の定義**

.. code-block:: xml

    <bean id="CL_I18N_PRICE"
        class="org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList">
        <property name="rowsByCodeList">
            <util:map>
                <entry key="en" value-ref="CL_PRICE_EN" />
                <entry key="ja" value-ref="CL_PRICE_JA" />
            </util:map>
        </property>
    </bean>
 
    <bean id="CL_PRICE_EN" class="org.terasoluna.gfw.common.codelist.SimpleMapCodeList">
        <property name="map">
            <util:map>
                <entry key="0" value="unlimited" />
                <entry key="10000" value="Less than \\10,000" />
                <entry key="20000" value="Less than \\20,000" />
                <entry key="30000" value="Less than \\30,000" />
                <entry key="40000" value="Less than \\40,000" />
                <entry key="50000" value="Less than \\50,000" />
            </util:map>
        </property>
    </bean>
 
    <bean id="CL_PRICE_JA" class="org.terasoluna.gfw.common.codelist.SimpleMapCodeList">
        <property name="map">
            <util:map>
                <entry key="0" value="上限なし" />
                <entry key="10000" value="10,000円以下" />
                <entry key="20000" value="20,000円以下" />
                <entry key="30000" value="30,000円以下" />
                <entry key="40000" value="40,000円以下" />
                <entry key="50000" value="50,000円以下" />
            </util:map>
        </property>
    </bean>
   

**プロパティファイル**

.. code-block:: properties

    simpleI18nCodeList.fallback.locale = en

**Controllerクラス**

.. code-block:: java

    ...
    
    @Controller
    public class OrderController {
        
        @Value("${simpleI18nCodeList.fallback.locale}") // (1)
        private Locale fallBackLocale;

        @RequestMapping(value = "price", method = RequestMethod.GET) 
        public String price(Model model, HttpServletRequest request) {
            model.addAttribute("requestLocale", RequestContextUtils
                .getLocale(request)); // (2)
            model.addAttribute("fallBackLocale",fallBackLocale); // (3)

            return "order/price";
        }
    }

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
   :header-rows: 1
   :widths: 10 90

   * - 項番
     - 説明
   * - | (1)
     - | リクエストで指定したロケールがコードリストに定義されていなかった場合に、どのロケールのコードリストを取得するかをプロパティファイルから取得し、``fallBackLocale`` 変数に設定する。
   * - | (2)
     - | ``org.springframework.web.servlet.support.RequestContextUtils`` 利用してリクエストで指定されたロケールを取得し、Modelに登録する。
         ``RequestContextUtils`` の ``getLocale`` メソッドは、引数に ``javax.servlet.http.HttpServletRequest`` を取るため、この場合は ``HttpServletRequest`` をハンドラメソッドの引数にとっても良い。
   * - | (3)
     - | (1) で取得した ``fallBackLocale`` をModelに登録する。

**テンプレートHTML実装例**

.. code-block:: html

    <select th:field="*{basePrice}">
        <option th:each="price : ${@CL_I18N_PRICE.asMap(requestLocale).isEmpty()} ? 
        ${@CL_I18N_PRICE.asMap(fallBackLocale)} : ${@CL_I18N_PRICE.asMap(requestLocale)}"
        th:value="${price.key}" th:text="${price.value}"></option> <!--/* (1) */-->
    </select>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
  :header-rows: 1
  :widths: 10 90

  * - 項番
    - 説明
  * - | (1)
    - | リクエストで指定したロケールに対応するコードリストを ``Map`` 形式で取得する。
      | リクエストで指定したロケールがコードリストに定義されていなかった場合、``fallbackLocale`` 変数に設定したロケールで対応するコードリストを ``Map`` 形式で取得する。

**出力HTML lang=en**

.. code-block:: html

    <select id="basePrice" name="basePrice">
        <option value="0">unlimited</option>
        <option value="1">Less than \\10,000</option>
        <option value="2">Less than \\20,000</option>
        <option value="3">Less than \\30,000</option>
        <option value="4">Less than \\40,000</option>
        <option value="5">Less than \\50,000</option>
    </select>

**出力HTML lang=ja**

.. code-block:: html

    <select id="basePrice" name="basePrice">
        <option value="0">上限なし</option>
        <option value="1">10,000円以下</option>
        <option value="2">20,000円以下</option>
        <option value="3">30,000円以下</option>
        <option value="4">40,000円以下</option>
        <option value="5">50,000円以下</option>
    </select>
   
**出力HTML lang=undefined**

.. code-block:: html

    <select id="basePrice" name="basePrice">
        <option value="0">unlimited</option> <!-- (1) -->
        <option value="1">Less than \\10,000</option>
        <option value="2">Less than \\20,000</option>
        <option value="3">Less than \\30,000</option>
        <option value="4">Less than \\40,000</option>
        <option value="5">Less than \\50,000</option>
    </select>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
  :header-rows: 1
  :widths: 10 90

  * - 項番
    - 説明
  * - | (1)
    - | リクエストで指定したロケールがコードリストに定義されていなかった場合に、``fallbackLocale`` 変数で指定した"en" が設定されるため、ロケールが"en"である ``CL_PRICE_EN`` コードリストが表示される。