開発に着手する前に作成しておく必要がある共通クラスです。
クラス、JSPで使用する変数を一箇所に定義しておきます。
package tutorial.common; public interface GlobalConstants { public static final String SERVLET_NAME = "jp"; public static final String REQID_NAME = "cid"; public static final String OP_NAME = "op"; }
後述のAbstractOptionsBuilderで使用する変数を一箇所に宣言します。
変数名は任意ですが、わかりやすくするためにOC_などの接頭子などを 決めておくと実装時に判別がしやすくなります。
package tutorial.common; public interface OptionsConstants { public static final int OC_SEXKBN = 100; public static final int OC_CITYCD = 102; public static final int OC_HOBBYCD = 103; }
これらの定数は開発を行っている最中に増えていくものです。
開発を行う前に「定数はここに、こういうネーミングルールで宣言していく」という ルールを作ることが重要です。
IPageListDecoratorは以下のインタフェースを持ち、一覧表示用のクラスを使用してページ制御を行うために使用されます。
Wisdomには省略時のDefaultPageListDecoratorという抽象クラスが定義してあるのでそれを実装して利用が可能になります。
/** * ページ・カウンタを描画します。<br> * 一般的な例では<br> * 1 2 3 4 5 6 7 8 <br> * のような形式の一覧形式表の画面上部または画面下部に表示されるページ・ナビゲーションになります。 * * @param rows 現在の行番号。開始位置は1 * @param totalPage 全ページ数 * @param perPageRows 1ページあたりの表示行数 * @param currentPageIndex 現在のページ位置 * @param hasPrevious 前ページを持つか否か * @param hasNext 次ページを持つか否か * @return ページ・カウンタ */ public String drawCounter(int rows, int totalPage, int perPageRows, int currentPageIndex, boolean hasPrevious, boolean hasNext); /** * 前ページリンクを描画します。<br> * 一般的な例では<br> * <<前へ<br> * のような形式のリンクになります。<br> * @param hasPrevioues 前ページを持つか否か * @return 前ページリンク */ public String drawPrevious(boolean hasPrevioues); /** * 次ページリンクを描画します。<br> * 一般的な例では<br> * >>次へ<br> * のような形式のリンクになります。<br> * @param hasNext 次ページを持つか否か * @return 次ページリンク */ public String drawNext(boolean hasNext); /** * イベント文字列から次ページ、前ページ、ページ指定かを判断し、遷移先のページ番号を取得します。<br> * * @param eventName * @param currentPageIndex 現在のページ番号 * @param toPageIndex このメソッド実行後に移動するページ番号 * @return 移動先のページ番号 */ public int changePageIndex(String eventName, int currentPageIndex,int toPageIndex); /** * 前ページ遷移のイベント文字列を取得します。<br> * * @return 前ページの遷移のイベント文字列 */ public String getPrevEventName () ; /** * 指定ページ遷移のイベント文字列を取得します。<br> * * @return 指定ページの遷移のイベント文字列 */ public String getMoveEventName () ; /** * 次ページ遷移のイベント文字列を取得します。<br> * * @return 指定ページの遷移のイベント文字列 */ public String getNextEventName () ;
このサンプルではExamplePageDecoratorとして実装しています。
コンストラクタの引数は一覧ページクラスが 前に、ページ移動、次にという挙動をJavaScriptで出力しますがその際のJavaScriptイベント名として使用されます。
一覧ページ遷移のデザイン、挙動を変更したい場合はDefaultPageListDecoratorをコピーして、任意のページ遷移クラスを 実装することができます。
package tutorial.common; import wisdomx.ui.render.DefaultPageListDecorator; public class ExamplePageDecorator extends DefaultPageListDecorator { protected ExamplePageDecorator(String prevName, String moveName, String nextName) { super(prevName, moveName, nextName); } }
AbstractOptionsBuilderはhtml radio、chekbox、selectなど共通で使用する部品の作成を局所化、隠蔽化することが 目的です。各機能の実装時(このクラスを利用する場合)OptionsConstantsで宣言した変数を使用して対応する部品を作成します。
import wisdom.core.application.IRequestHandler; import wisdomx.ui.builder.AbstractOptionsBuilder; import wisdomx.ui.object.Option; import wisdomx.ui.object.Select; public class OptionsBuilder extends AbstractOptionsBuilder implements OptionsConstants { private static final String SQL_CITYCD = "select CITYCD, CITYNM from MCITY "; private static final String SQL_HOBBYCD = "select HOBBYCD, HOBBYNM from MHOBBY "; protected OptionsBuilder(IRequestHandler rh) { super(rh); } public Select build(int optionType, String optionsName) throws Exception { Select select = new Select(optionsName); String sql = null; switch (optionType) { case OC_CITYCD : sql = SQL_CITYCD ; break; case OC_HOBBYCD : sql = SQL_HOBBYCD ; break; case OC_SEXKBN : return createFromArray(select, STR_SEXKBN); } PreparedStatement ps = rh.getConnection().prepareStatement(sql); ResultSet rs = ps.executeQuery(); while(rs.next()) { select.add(new Option(rs.getString(1).trim(), rs.getString(2).trim())); } rs.close(); ps.close(); return select; } public Select build(int optionType, String optionsName, String key) throws Exception{ return null; } public Select build(int optionType, String optionsName, String[] keys) throws Exception{ return null; } private Select createFromArray(Select select, String[][] array) { for (int i = 0; i < array.length; i++) { select.add(new Option(array[i][0], array[i][1])); } return select; } /** 性別 */ public static final String[][] STR_SEXKBN = new String[][]{ {"1","男性"}, {"2","女性"} }; }
部品は「必ずこのクラスで作成しなくてはならない」というものではありません。
必要に応じて各機能で部品作成を実装する場面は 出てきますが、変更があった場合の影響を考慮して極力避けるべきです。
また「ここで作る」というルールを作成することで実装方法が 自然と決まってくるので「どこでどういった形で実装するか?」などを考える必要がなくなります。
作成した共通クラスはすべてFactory化しインスタンスの生成は各機能から隠蔽化します。
各機能の実装時にはFactoryから取得できるクラス、インターフェースがどのような役割をするのかを理解していればよく、変更があった場合の 修正箇所を減らすことができます。
package tutorial.common; import wisdom.core.application.IRequestHandler; import wisdomx.ui.builder.IOptionsBuilder; import wisdomx.ui.render.DefaultMessageLoader; import wisdomx.ui.render.IMessageLoader; import wisdomx.ui.render.IPageListDecorator; public class Factory implements OptionsConstants { private static IPageListDecorator pc = new ExamplePageDecorator("prev","move","next"); static class SimpleMessageLoader extends DefaultMessageLoader {} private static IMessageLoader messageLoader = new SimpleMessageLoader(); private Factory() { super(); } public static IPageListDecorator getPageDecorator() { return pc; } public static IOptionsBuilder getOptionsBuilder(IRequestHandler rh) throws Exception { return new OptionsBuilder(rh); } public static IMessageLoader getMessageLoader() { return messageLoader; }
Defineクラスはアプリケーションに存在する1項目をクラスとして定義し、項目の値のチェック、表示メッセージ、htmlタグの生成などに 使用します。。
public static final Define USERID = new Define(CHAR_ALPHA_NUMERIC, "USERID", 20, "ユーザーID"); public static final Define USERNAME = new Define(CHAR, "USERNAME", 50, "ユーザー名");
入力された項目の妥当性チェック、範囲チェックを行うクラスです。StringCheckerはDefineクラスで定義された型、範囲の検査を行い 結果をエラーメッセージ、MessageListクラスに戻します。
protected void _validate() throws Exception { StringChecker sc = new StringChecker(); int result = 0; result += sc.checkNotEmpty(USERID, fo.getUserid(),fo); result += sc.checkNotEmpty(USERNAME, fo.getUsername(),fo); result += sc.checkNotEmpty(PASSWORD, fo.getPassword(),fo); 略
Defineクラスの定義はDataDictionaryインターフェースにまとめて行います。
public interface DataDictionary extends Types { public static final Define USERID = new Define(CHAR_ALPHA_NUMERIC, "USERID", 20, "ユーザーID"); public static final Define USERNAME = new Define(CHAR, "USERNAME", 50, "ユーザー名");
重要なのはアプリケーションで使用する項目を洗い出し、重複することなく整理し定義することです。
アプリケーションからは項目の 属性はDefineクラスを参照して行うので、実装時に型を意識する必要が減り変更にも対応が柔軟になります。
wisdomx.ui.render.TagクラスはDefine、値を使用してinputタグを生成することができます。
但しinputタグデザインを変更したい、 Scriptを挿入できるようにしたい、inputタグの長さは均一にしたい、などプロジェクトによって要求は変わります。
そのような場合のサンプルとしてtutorial.common.TagRendorが用意されています。
このクラスはそのまま利用もできますが アプリケーションにより、出力するhtmlタグが変わりますので、このクラスをコピーして独自の実装を行うことができます。
プロジェクトに応じて少しづつ要求は変わります。個々に違う実装部分を切り出し、「このクラスで行う」というルール付けが重要です。
メッセージは.proptiesファイルに定義します。
PropertyEncoding=SJIS DCG0010W=登録可能なカテゴリーがありません。 DCG0011W=トピックはありません。 USM0010I=登録されているユーザーはいません。 USM0011E=入力されたユーザーIDはすでに登録されています。
.propertieファイルの場所はwisdom_config.xmlに指定します。
例) wisdom_config.xmlの設定
<parameter category='message' id='app.message.resource' value='tutorial.common.AppMessageResource' />
.propertiesファイルは日本語で登録ができますが、文字の並びによって表示時に文字化けする場合があります。 文字化けした文字の後ろに\(エスケープ文字)を入れることで対応できます。