5.14. コードリスト¶
Caution
本バージョンの内容は既に古くなっています。最新のガイドラインはこちらからご参照ください。
目次
5.14.1. Overview¶
コードリストとは、「コード値(value)とその表示名(label)」の集合である。
画面のセレクトボックスなどコード値を画面で表示する際のラベルへのマッピング表として利用される。
共通ライブラリでは、
- xmlファイルやDBに定義されたコードリストをアプリケーション起動時に読み込みキャッシュする機能
- JSPやJavaクラスからコードリストを参照する機能
- コードリストを用いて入力チェックするを行う機能
を提供している。
また、応用的な使い方として、
- コードリストの国際化対応
- キャッシュされたコードリストのリロード
もサポートしている。
Note
標準でリロードが可能なのは、DBに定義されたコードリストを使用する場合のみである。
共通ライブラリでは、以下4種類のコードリスト実装を提供している。
種類 | 内容 | 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.CodeList
を提供している。
共通ライブラリで提供しているコードリストのクラス図構成を以下に示す。
5.14.2. How to use¶
本項では、各種コードリストを使用する上での設定や実装方法を記述する。
- SimpleMapCodeListの使用方法
- NumberRangeCodeListの使用方法
- JdbcCodeListの使用方法
- EnumCodeListの使用方法
- SimpleI18nCodeListの使用方法
- コードリストを用いたコード値の入力チェック
5.14.2.1. SimpleMapCodeListの使用方法¶
org.terasoluna.gfw.common.codelist.SimpleMapCodeList
とは、
xmlファイルに定義したコード値をアプリケーション起動時に読み込み、そのまま使用するコードリストである。
SimpleMapCodeListのイメージ
5.14.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" /> より上で設定する必要がある。 |
5.14.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)がJSPで使用可能となる。 |
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>
出力画面
5.14.2.1.3. Javaクラスでのコードリスト使用¶
Javaクラスでコードリストを利用する場合、 javax.inject.Inject
アノテーションと、
javax.inject.Named
アノテーションを設定してコードリストをインジェクションする。
@Named
にコードリスト名を指定する。
import javax.inject.Named;
import org.terasoluna.fw.common.codelist.CodeList;
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 形式で取得する。 |
5.14.2.2. NumberRangeCodeListの使用方法¶
org.terasoluna.gfw.common.codelist.NumberRangeCodeList
とは、
アプリケーション起動時に、指定した数値の範囲をリストにするコードリストである。
主に数だけのセレクトボックス、月や日付などのセレクトボックスに使用することを想定している。
NumberRangeCodeListのイメージ
Tip
NumberRangeCodeListはアラビア数字のみ対応しており、漢数字やローマ数字には対応していない。 漢数字やローマ数字を表示したい場合はJdbcCodeList、SimpleMapCodeListに定義することで対応可能である。
NumberRangeCodeListには、以下の特徴がある。
- Fromの値をToの値より小さくする場合、昇順にinterval分増加した値をFrom~Toの範囲分リストにする。
- Toの値をFromの値より小さくする場合、降順にinterval分減少した値をTo~Fromの範囲分リストにする。
- 増加分(減少分)はintervalを設定することで変更できる。
ここでは、昇順のNumberRangeCodeList
について説明をする。
降順のNumberRangeCodeList
とインターバルの変更方法については、「NumberRangeCodeListのバリエーション」を参照されたい。
5.14.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”が設定される。
|
5.14.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>
出力画面
5.14.2.3. JdbcCodeListの使用方法¶
org.terasoluna.gfw.common.codelist.JdbcCodeList
とは、アプリケーション起動時にDBから値を取得し、
コードリストを作成するクラスである。このリストはキャッシュされる。
また、取得する値はリロードにより動的に変更できる。詳細は コードリストをリロードする場合 参照されたい。
JdbcCodeListのイメージ
5.14.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="CL_AUTHORITIES" class="org.terasoluna.gfw.common.codelist.JdbcCodeList"> <!-- (1) -->
<property name="dataSource" ref="dataSource" />
<property name="querySql"
value="SELECT authority_id, authority_name FROM authority ORDER BY authority_id" /> <!-- (2) -->
<property name="valueColumn" value="authority_id" /> <!-- (3) -->
<property name="labelColumn" value="authority_name" /> <!-- (4) -->
</bean>
項番 | 説明 |
---|---|
(1)
|
JdbcCodeListクラスをbean定義する。
|
(2)
|
querySqlプロパティに取得するSQLを記述する。その際、 必ず「ORDER BY」を指定し、順序を確定させること。
「ORDER BY」を指定しないと、取得する度に順序が変わってしまう。
|
(3)
|
valueColumnプロパティに、MapのKeyに該当する値を設定する。この例ではauthority_idを設定している。
|
(4)
|
labelColumnプロパティに、MapのValueに該当する値を設定する。この例ではauthority_nameを設定している。
|
5.14.2.3.2. 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>
出力画面
5.14.2.4. EnumCodeListの使用方法¶
org.terasoluna.gfw.common.codelist.EnumCodeList
は、
Enum
クラスに定義した定数からコードリストを作成するクラスである。
Note
以下の条件に一致するアプリケーションでコードリストを扱う場合は、
EnumCodeList
を使用して、コードリストのラベルをEnum
クラスで管理することを検討してほしい。
コードリストのラベルをEnum
クラスで管理することで、
コード値に紐づく情報と操作をEnum
クラスに集約する事ができる。
- コード値を
Enum
クラスで管理する必要がある(つまり、Javaのロジックでコード値を意識した処理を行う必要がある) - UIの国際化(多言語化)の必要がない
以下に、EnumCodeList
の使用イメージを示す。
Note
EnumCodeList
では、Enum
クラスからコードリストを作成するために必要な情報(コード値とラベル)を取得するためのインタフェースとして、
org.terasoluna.gfw.common.codelist.EnumCodeList.CodeListItem
インタフェースを提供している。
EnumCodeList
を使用する場合は、作成するEnum
クラスでEnumCodeList.CodeListItem
インタフェースを実装する必要がある。
5.14.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)
|
コードリストとして使用する
が定義されている。 |
(2)
|
定数を定義する。 定数を生成する際に、コードリストを作成するために必要な情報(コード値とラベル)を指定する。 上記例では、以下の3つの定数を定義している。
Note
|
(3)
|
コードリストを作成するために必要な情報(コード値とラベル)を保持するプロパティを用意する。 |
(4)
|
コードリストを作成するために必要な情報(コード値とラベル)を受け取るコンストラクタを用意する。 |
(5)
|
定数が保持するコード値を返却する。 このメソッドは、 |
(6)
|
定数が保持するラベルを返却する。 このメソッドは、 |
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を指定する。 |
5.14.2.5. SimpleI18nCodeListの使用方法¶
org.terasoluna.gfw.common.codelist.i18n.SimpleI18nCodeList
は、国際化に対応しているコードリストである。
ロケール毎にコードリストを設定することで、ロケールに対応したコードリストを返却できる。
SimpleI18nCodeListのイメージ
5.14.2.5.1. コードリスト設定例¶
SimpleI18nCodeList
は行が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
を設定する」方法でコードリストを設定することを推奨する。
上記例の料金を選択するセレクトボックスの場合を行単位で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.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.JdbcCodeList"> <!-- (4) -->
<property name="dataSource" ref="dataSource" />
<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" class="org.terasoluna.gfw.common.codelist.JdbcCodeList"> <!-- (5) -->
<property name="dataSource" ref="dataSource" />
<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)
|
ロケールが”en”であるbean定義
CL_PRICE_EN について、コードリストクラスを JdbcCodeList で設定している。 |
(5)
|
ロケールが”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円以下
|
Warning
現時点で SimpleI18nCodeList
はreloadableに対応していない。
SimpleI18nCodeList
が参照している JdbcCodeList
(reloadableなCodeList)をリロードしても、 SimpleI18nCodeList
には反映されないことに注意。
もし、reloadableに対応したい場合は独自実装する必要がある。
実装方法については、 コードリストを独自カスタマイズする方法 を参照されたい。
5.14.2.5.2. JSPでのコードリスト使用¶
基本的な設定は、前述した 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
出力画面 lang=ja
5.14.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を取得することができる。
|
5.14.2.6. コードリストを用いたコード値の入力チェック¶
入力値がコードリスト内に定義されたコード値であるかどうかチェックするような場合、
共通ライブラリでは、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.RELEASEorg.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
を作成してメッセージを定義する必要がある。
5.14.2.6.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以外の文字が格納されている場合、エラーになる。
Tip
@ExistInCodeList
の入力チェックでサポートしている型は、 String
または Character
のみである。
そのため、 @ExistInCodeList
をつけるフィールドは意味的に整数型であっても、Stringで定義する必要がある。(年・月・日等)
5.14.3. How to extend¶
5.14.3.1. JdbcCodeListの読み込む件数が大きい場合¶
JdbcCodeListの読み込む件数が大きい(数百)場合、Webアプリの起動に時間が掛かる。
原因は、DB問い合わせ時に全件取得することがあり、DBからリストを取得する時間がかかってしまうためである。 (fetchSizeのデフォルト設定が、全件取得になっている場合がある。)
この問題は、fetchSizeを適切な値に指定することで解決できる。
fetchSizeを変更するには org.springframework.jdbc.core.JdbcTemplate
のfetchSizeを設定する必要がある。
以下に実装例を示す。
bean定義ファイル(xxx-infra.xml)の定義
<bean id="jdbcTemplateForCodeList" class="org.springframework.jdbc.core.JdbcTemplate" > <!-- (1) -->
<property name="dataSource" ref="dataSource" />
<property name="fetchSize" value="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" />
<property name="valueColumn" value="authority_id" />
<property name="labelColumn" value="authority_name" />
</bean>
項番 | 説明 |
---|---|
(1)
|
org.springframework.jdbc.core.JdbcTemplate クラスをbean定義する。独自にfetchSizeを設定するために必要となる。
|
(2)
|
fetchSizeを設定する。適切な値を設定すること。
|
(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分作成する。
|
5.14.3.2. コードリストをリロードする場合¶
前述した共通ライブラリで提供しているコードリストは、アプリケーション起動時に読み込まれ、それ以降は、基本的に更新されない。 しかし、コードリストのマスタデータを更新した時、コードリストも更新したい場合がある。
例:JdbcCodeListを使用して、DBのマスタを変更した時にコードリストの更新を行う場合。
共通ライブラリでは、 org.terasoluna.gfw.common.codelist.ReloadableCodeList
インタフェースを用意している。
上記インタフェースを実装したクラスは、refreshメソッドを実装しており、refreshメソッドを呼ぶことでコードリストの更新が可能となる。
JdbcCodeListは、ReloadableCodeListインターフェースを実装しているため、コードリストの更新ができる。
コードリストの更新方法としては、以下2点の方法がある。
- Task Schedulerで実現する方法
- Controller(Service)クラスでrefreshメソッドを呼び出す方法
本ガイドラインでは、Springから提供されているTask Schedulerを使用して、コードリストを定期的にリロードする方式を基本的に推奨する。
ただし、任意のタイミングでコードリストをリフレッシュする必要がある場合はControllerクラスでrefreshメソッドを呼び出す方法で実現すればよい。
Note
ReloadableCodeListインターフェースを実装しているコードリストについては、 コードリスト種類一覧 を参照されたい。
5.14.3.2.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" class="org.terasoluna.gfw.common.codelist.JdbcCodeList">
<property name="dataSource" ref="dataSource" />
<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を参照されたい。
|
5.14.3.2.2. Controller(Service)クラスでrefreshメソッドを呼び出す方法¶
refreshメソッドを直接呼び出す場合について、 JdbcCodeListのrefreshメソッドをServiceクラスで呼び出す場合の実装例を、以下に示す。
bean定義ファイル(xxx-codelist.xml)の定義
<bean id="CL_AUTHORITIES" class="org.terasoluna.gfw.common.codelist.JdbcCodeList">
<property name="dataSource" ref="dataSource" />
<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 CodeListContoller {
@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メソッドを実行することで、コードリストが更新される。
|
5.14.3.3. コードリストを独自カスタマイズする方法¶
共通ライブラリで提供している4種類のコードリストで実現できないコードリストを作成したい場合、コードリストを独自にカスタマイズすることができる。 独自カスタマイズする場合、作成できるコードリストの種類と実装方法について、以下の表に示す。
項番 | 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”の順で格納される。)
コードリストクラス
@Component("CL_YEAR") // (1)
public class DepYearCodeList extends AbstractCodeList { // (2)
@Inject
JodaTimeDateFactory dateFactory; // (3)
@Override
public Map<String, String> asMap() { // (4)
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)
|
@Component で、コードリストをコンポーネント登録する。Valueに
"CL_YEAR" を指定することで、bean定義で設定したコードリストインターセプトによりコードリストをコンポーネント登録する。 |
(2)
|
org.terasoluna.gfw.common.codelist.AbstractCodeList を継承する。今年と来年の年のリストを作る時、動的にシステム日付から算出して作成しているため、リロードは不要。
|
(3)
|
システム日付のDateクラスを作成する
org.terasoluna.gfw.common.date.jodatime.JodaTimeDateFactory をインジェクトしている。JodaTimeDateFactory を利用して今年と来年の年を取得することができる。事前に、bean定義ファイルにDataFactory実装クラスを設定する必要がある。
|
(4)
|
asMap() メソッドをオーバライドして、今年と来年の年のリストを作成する。作成したいコードリスト毎に実装が異なる。
|
jspの実装例
<form:select path="mostRecentYear" items="${CL_YEAR}" /> <!-- (5) -->
項番 | 説明 |
---|---|
(5)
|
items属性にコンポーネント登録した
"CL_YEAR" を ${} プレースホルダー で指定することで、該当のコードリストを取得することができる。 |
出力HTML
<select id="mostRecentYear" name="mostRecentYear">
<option value="2013">2013</option>
<option value="2014">2014</option>
</select>
出力画面
Note
リロード可能であるCodeListを独自カスタマイズする場合、スレッドセーフになるように実装すること。
5.14.4. Appendix¶
5.14.4.1. SimpleI18nCodeListのコードリスト設定方法¶
SimpleI18nCodeListのコードリスト設定について、 SimpleI18nCodeListの使用方法 で設定されているコードリスト設定の他に2つ設定方法がある。 料金を選択するセレクトボックスの場合の例を用いて、それぞれの設定方法を説明する。
5.14.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はロケールに対応したラベルである。
|
5.14.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はロケールに対応したラベルである。 |
5.14.4.2. NumberRangeCodeListのバリエーション¶
5.14.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>
出力画面
5.14.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>
出力画面
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
はコードリストに格納されない。