4.8. コードリスト

目次

4.8.1. Overview

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

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

共通ライブラリでは、

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

を提供している。

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

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

もサポートしている。

Note

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


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

コードリスト種類一覧
種類 内容 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 を提供している。

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

codelist class diagram

Picture - Image of codelist class diagram


4.8.2. How to use

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


4.8.2.1. SimpleMapCodeListの使用方法

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

SimpleMapCodeListのイメージ

codelist simple

4.8.2.1.1. コードリスト設定例

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

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

 <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>
項番 説明
(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を行う必要がある。

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

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

4.8.2.1.2. JSPでのコードリスト使用

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

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

 <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>
項番 説明
(1)
適用対象のパスを設定する。
(2)
CodeListInterceptor クラスをbean定義する。
(3)
自動でリクエストスコープに設定する、コードリストのbeanIDのパターンを設定する。
パターンには java.util.regex.Pattern で使用する正規表現を設定すること。
上記例では、idが”CL_XXX”形式で定義されているデータのみを対象とする。その場合、idが”CL_”で始まらないbean定義は取り込まれない。
“CL_”で定義したbeanIDは、リクエストスコープに設定されるため、JSPで容易に参照できる。

codeListIdPatternプロパティは省略可能である。
codeListIdPatternを省略した場合は、すべてのコードリスト(org.terasoluna.gfw.common.codelist.CodeListインタフェースを実装しているbean)がリクエストスコープに設定される。

Warning

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

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

例外時に遷移する画面でコードリストを利用したい場合は、ハンドラメソッドで例外を捕捉(try-catch)するか、 JSPから直接コードリストBeanを参照する を利用してコードリストを取得することを検討されたい。

例外ハンドリングの方法については、 例外のハンドリング方法 を参照されたい。


jspの実装例

<form:select path="orderStatus">
  <form:option value="" label="--Select--" /> <!-- (4) -->
  <form:options items="${CL_ORDERSTATUS}" /> <!-- (5) -->
</form:select>
項番 説明
(4)
セレクトボックスの先頭にダミーの値を設定する場合、valueに空文字を指定すること。
(5)
コードリストを定義したbeanIDを指定する。

出力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>

出力画面

codelist selectbox

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

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

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

4.8.2.2. NumberRangeCodeListの使用方法

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

NumberRangeCodeListのイメージ

codelist number

Tip

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


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

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

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


4.8.2.2.1. コードリスト設定例

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

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

4.8.2.2.2. JSPでのコードリスト使用

設定例の詳細は、前述した JSPでのコードリスト使用 を参照されたい。

jspの実装例

<form:select path="depMonth" items="${CL_MONTH}" />

出力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>

出力画面

codelist numberrenge

4.8.2.3. JdbcCodeListの使用方法

org.terasoluna.gfw.common.codelist.JdbcCodeList とは、アプリケーション起動時にDBから値を取得し、コードリストを作成するクラスである。
JdbcCodeList はアプリケーション起動時にキャッシュを作るので、リスト表示時はDBアクセスによる遅延がない。
起動時の読み込み時間を抑えたいならば、取得数の上限を設定するとよい。
JdbcCodeList には org.springframework.jdbc.core.JdbcTemplate を設定するフィールドがある。
JdbcTemplatefetchSize に上限を設定すれば、その分だけのレコードが起動時に読み込まれる。
なお、取得する値はリロードにより動的に変更できる。詳細は コードリストをリロードする場合 参照されたい。

JdbcCodeListのイメージ

codelist simple

4.8.2.3.1. コードリスト設定例

テーブル(authority)の定義

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

bean定義ファイル(xxx-codelist.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>
項番 説明
(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を設定している。

4.8.2.3.2. JSPでのコードリスト使用

下記に示す設定の詳細について、前述した JSPでのコードリスト使用 を参照されたい。

jspの実装例

<form:checkboxes items="${CL_AUTHORITIES}"/>

出力HTML

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

出力画面

codelist checkbox

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

下記に示す設定の詳細について、前述した Javaクラスでのコードリスト使用 を参照されたい。


4.8.2.4. EnumCodeListの使用方法

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

Note

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

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

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

codelist enum

Note

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

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


4.8.2.4.1. コードリスト設定例

Enumクラスの作成

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

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;
    }

}
項番 説明
(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を定義する。 以下に定義例を示す。

<bean id="CL_ORDERSTATUS"
      class="org.terasoluna.gfw.common.codelist.EnumCodeList"> <!-- (7) -->
    <constructor-arg value="com.example.domain.model.OrderStatus" /> <!-- (8) -->
</bean>
項番 説明
(7)
コードリストの実装クラスとして、EnumCodeListクラスを指定する。
(8)
EnumCodeListクラスのコンストラクタに、EnumCodeList.CodeListItemインタフェースを実装したEnumクラスのFQCNを指定する。

4.8.2.4.2. JSPでのコードリスト使用

JSPでコードリストを使用する方法については、前述した JSPでのコードリスト使用 を参照されたい。


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

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


4.8.2.5. 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)のイメージ

codelist i18n

4.8.2.5.1. コードリスト設定例

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

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

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毎の ReloadableCodeListJdbcCodeList)を設定する

Note

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

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


Bean定義ファイル(xxx-codelist.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>
項番 説明
(1)
rowsByCodeListプロパティにkeyがjava.lang.LocaleのMapを設定する。
Mapには、keyにロケール、value-refにロケールに対応したコードリストクラスの参照先を指定する。
Mapのvalueは各ロケールに対応したコードリストクラスを参照する。

Locale毎にSimpleMapCodeListを用意する場合のBean定義ファイル(xxx-codelist.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>
項番 説明
(2)
ロケールが”en”であるbean定義 CL_PRICE_EN について、コードリストクラスを SimpleMapCodeList で設定している。
(3)
ロケールが”ja”であるbean定義 CL_PRICE_JA について、コードリストクラスを SimpleMapCodeList で設定している。

Locale毎にJdbcCodeListを用意する場合のBean定義ファイル(xxx-codelist.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>
項番 説明
(4)
更新可能なコードリストを行に持つ場合は、SimpleReloadableI18nCodeList を利用する。
(5)
ロケールが”en”であるbean定義 CL_PRICE_EN について、コードリストクラスを JdbcCodeList で設定している。
(6)
ロケールが”ja”であるbean定義 CL_PRICE_JA について、コードリストクラスを JdbcCodeList で設定している。

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

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円以下

4.8.2.5.2. JSPでのコードリスト使用

基本的な設定は、前述した JSPでのコードリスト使用 と同様のため、説明は省略する。

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

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

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

  <!-- omitted -->

</mvc:interceptors>
項番 説明
(1)
リクエストのロケールがコードリスト定義されていなかった場合、
fallbackToプロパティに設定されたロケールでコードリストを取得する。
fallbackToプロパティが設定されていない場合、JVMのデフォルトロケールがfallbackToプロパティとして使用される。
fallbackToプロパティに設定されたロケールでも、コードリストが取得されない場合、WARNログを出力し、空のMapを返却する。

jspの実装例

<form:select path="basePrice" items="${CL_I18N_PRICE}" />

出力HTML lang=en

<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

<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

codelist i18n en

出力画面 lang=ja

codelist i18n ja

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

基本的な設定は、前述した Javaクラスでのコードリスト使用 と同様のため、説明は省略する。

@RequestMapping("orders")
@Controller
public class OrderController {

    @Inject
    @Named("CL_I18N_PRICE")
    I18nCodeList priceCodeList;

    // ...

    @RequestMapping(method = RequestMethod.POST, params = "confirm")
    public String confirm(OrderForm form, Locale locale) {
        // ...
        String priceMassage = getPriceMessage(form.getPriceCode(), locale);
        // ...
    }

    private String getPriceMessage(String targetPrice, Locale locale) {
         return priceCodeList.asMap(locale).get(targetPrice);  // (1)
    }

}
項番 説明
(1)
I18nCodeList#asMap(Locale)で対応したロケールのMapを取得することができる。

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

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

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

jspの実装例

Order Status : ${f:h(CL_ORDERSTATUS[orderForm.orderStatus])}
項番 説明
(1)
コードリストを定義したbeanID(この例では CL_ORDERSTATUS ) を属性名として、コードリスト( java.util.Map インタフェース)を取得する。 取得した Map インタフェースのキーとしてコード値(この例では orderStatus に格納された値) を指定することで、対応するコード名を表示することができる。

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

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

BeanValidationや、メッセージ出力方法の詳細については、 入力チェック を参照されたい。

@ExistInCodeListアノテーションを使用して入力チェックを行う場合は、 @ExistInCodeList用の「エラーメッセージの定義」を行う必要がある。

ブランクプロジェクト からプロジェクトを生成した場合は、 xxx-web/src/main/resourcesの直下のValidationMessages.propertiesファイルの中に以下のメッセージが定義されている。 メッセージは、アプリケーションの要件に合わせて変更すること。

org.terasoluna.gfw.common.codelist.ExistInCodeList.message = Does not exist in {codeListId}

Note

terasoluna-gfw-common 5.0.0.RELEASEより、 メッセージのプロパティキーの形式を、Bean Validationのスタンダードな形式(アノテーションのFQCN + .message)に変更している。

バージョン メッセージのプロパティキー
version 5.0.0.RELEASE以降
org.terasoluna.gfw.common.codelist.ExistInCodeList.message
version 1.0.x.RELEASE
org.terasoluna.gfw.common.codelist.ExistInCodeList

version 1.0.x.RELEASEからversion 5.0.0.RELEASE以降にバージョンアップする際に、 アプリケーション要件に合わせてメッセージを変更している場合は、 プロパティキーの変更が必要になる。

Note

terasoluna-gfw-common 1.0.2.RELEASEより、 @ExistInCodeListのメッセージを定義したValidationMessages.propertiesを、 jarファイルの中に含めないようにしている。 これは、「ValidationMessages.propertiesが複数存在する場合にメッセージが表示されないバグ」を修正するためである。

version 1.0.1.RELEASE以前からversion 1.0.2.RELEASE以降にバージョンアップする際に、 terasoluna-gfw-commonのjarの中に含まれるValidationMessages.propertiesに定義しているメッセージを使用している場合は、 ValidationMessages.propertiesを作成してメッセージを定義する必要がある。


4.8.2.7.1. @ExistInCodeList の設定例

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

bean定義ファイル(xxx-codelist.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オブジェクト

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

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

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

Note

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

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

また、@ExistInCodeListはコレクション内の値には対応していないため、複数選択可能な画面項目(チェックボックスや複数選択ドロップダウンなど)に@ExistInCodeListアノテーションを対応させるためには実装を工夫する必要がある。 詳細については コレクション内の値をBean Validationのアノテーションを使用してチェックする方法 を参照されたい。


4.8.3. How to extend

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

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

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

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

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

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

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

本ガイドラインでは、Springから提供されているTask Schedulerを使用して、コードリストを定期的にリロードする方式を基本的に推奨する。

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

Note

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


4.8.3.1.1. Task Schedulerで実現する方法

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

bean定義ファイル(xxx-codelist.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>
項番 説明
(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を参照されたい。

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

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

bean定義ファイル(xxx-codelist.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クラス

@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";
    }
}
項番 説明
(1)
ReloadableCodeListクラスのrefreshメソッドを実行するServiceクラスをインジェクションする。
(2)
ReloadableCodeListクラスのrefreshメソッドを実行するServiceクラスのrefreshメソッドを実行する。

Serviceクラス

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

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

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

    @Override
    public void refresh() { // (6)
        codeListItem.refresh(); // (7)
    }
}
項番 説明
(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 をセットして実行すれば良い。


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

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

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

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

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

コードリストクラス

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

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

<bean id="CL_YEAR" class="com.example.sample.domain.codelist.DepYearCodeList"> <!-- (1) -->
    <property name="dateFactory" ref="dateFactory" /> <!-- (2) -->
</bean>
項番 説明
(1)
作成したコードリストクラスをbean定義する。
id に CL_YEAR を指定することで、bean定義で設定した CodeListInterceptor によりコードリストをコンポーネント登録する。
(2)
システム日付のDateクラスを作成する JodaTimeDateFactory を設定する。
事前に、bean定義ファイルにDataFactory実装クラスを設定する必要がある。

jspの実装例

<form:select path="mostRecentYear" items="${CL_YEAR}" /> <!-- (1) -->
項番 説明
(1)
items属性にコンポーネント登録した CL_YEAR${} プレースホルダー で指定することで、該当のコードリストを取得することができる。

出力HTML

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

出力画面

customized codelist

Note

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


4.8.4. Appendix

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

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

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

bean定義ファイル(xxx-codelist.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>
項番 説明
(1)
rowsプロパティに対して、”MapのMap”を設定する。外側のMapのkeyはjava.lang.Localeである。
内側のMapのkeyはコード値、valueはロケールに対応したラベルである。

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

bean定義ファイル(xxx-codelist.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>
項番 説明
(1)
columnsプロパティに対して、”MapのMap”を設定する。外側のMapのkeyはコード値である。
内側のMapのkeyはjava.lang.Locale、valueはロケールに対応したラベルである。

4.8.4.2. NumberRangeCodeListのバリエーション

4.8.4.2.1. 降順のNumberRangeCodeListの作成

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

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

jspの実装例

<form:select path="birthYear" items="${CL_BIRTH_YEAR}" />

出力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>

出力画面

codelist numberrenge2

4.8.4.2.2. NumberRangeCodeListのインターバルの変更

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

bean定義ファイル(xxx-codelist.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>
項番 説明
(1)
増加(減少)値を指定する。この指定によって、interval値を増加(減少)した値を、From~Toの範囲内でコードリストとして格納する。
上記の例だと、コードリストには10,20,30,40,50の順で格納される。

jspの実装例

<form:select path="quantity" items="${CL_BULK_ORDER_QUANTITY_UNIT}" />

出力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>

出力画面

codelist numberrenge3

Note

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

具体的には、

<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はコードリストに格納されない。

4.8.4.3. JSPから直接コードリストBeanを参照する

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

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

Note

国際化対応のため SimpleI18nCodeList を使用している場合は SimpleI18nCodeListをJSPから直接参照する方法 で紹介している方法を参照されたい。 JSPから直接コードリストBeanを参照する を使用する場合は、CodeListInterceptor が実施しているような、SimpleI18nCodeListasMap メソッドに渡すロケールを決定するロジックを独自に実装する必要があるためである。

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

  <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>
項番 説明
(1)
CodeListInterceptor の設定があれば、削除する。

bean定義ファイル(xxx-codelist.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>

jspの実装例

<spring:eval var="statuses" expression="@CL_ORDERSTATUS.asMap()"/> <!-- (1) -->
<form:select items="${statuses}" path="orderStatus" />
項番 説明
(1)
SpELにより取得した CodeList 型Beanの asMap メソッドにより、Map 形式で取得することができる。

出力HTML

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

4.8.4.3.1. SimpleI18nCodeListをJSPから直接参照する方法

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

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

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

bean定義ファイル(xxx-codelist.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>

プロパティファイル

simpleI18nCodeList.fallback.locale = en

Controllerクラス

...

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

jspの実装例

<spring:eval var="price" expression="@CL_I18N_PRICE.asMap(requestLocale).isEmpty() ? @CL_I18N_PRICE.asMap(fallBackLocale) : @CL_I18N_PRICE.asMap(requestLocale)" /> <!-- (1) -->
<form:select path="basePrice" items="${price}" />
項番 説明
(1)
リクエストで指定したロケールに対応するコードリストを Map 形式で取得する。
リクエストで指定したロケールがコードリストに定義されていなかった場合、fallbackLocale 変数に設定したロケールで対応するコードリストを Map 形式で取得する。

出力HTML lang=en

<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

<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

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