サポート > リポジトリ > 業務ロジック > 入力チェック・整合性チェック
ja | en

複雑な入力チェックや整合性チェックをスクリプトで実現する方法を説明します。

入力チェック処理をスクリプトコードとして記述することができます。

図1 スクリプト記述欄

ここに書いた処理は、その他の(必須チェックや、文字数チェックといった設定で記述できる)チェックの後に実行されます。

正確には、入力チェックの最後の処理となります。

Designerでスクリプトを修正すると、開発機上のアプリケーションへ即座に反映されます。ビルド処理なしで修正を確認することができます。

スクリプト内では、モデル名に対応した「オブジェクト」を利用できます。

WagbyではWebフォームから入力された値は「プレゼンテーションモデル」が管理しています。

スクリプト内では${モデル名_p}という表記で扱います。すべての値は文字列型になっています。

プレゼンテーションモデルの操作では、項目名の末尾に ".content" を付与することで、入力文字列を取得することができます。

次の例は、モデル schedule の日付項目 sch_date の入力が "H25" で始まる場合はエラーにする、というスクリプトです。

/* 日付を取り出す。*/
var s = 
    (schedule_p.schDate !== null) ? schedule_p.schDate.content : null; 
/* slice は JavaScript が提供する */
if (s !== null && s.slice(0,3)=="H25") { 
    var error = new Jfcerror();
    error.content = "平成25年はまだ入力できません。";
    p.errors.addJfcerror(error);
}

画面に表示するメッセージは次の3種類を利用することができます。

INFO

処理が正常に終了した場合のメッセージです。青枠にメッセージが表示されます。

var info = new Jfcinfo();
info.content="...";
p.errors.addJfcinfo(info);

ERROR

エラーメッセージです。赤枠にメッセージが表示されます。

var error = new Jfcerror();
error.content="...";
p.errors.addJfcerror(error);

国際化

メッセージの国際化にも対応しています。

エラーメッセージファイル $(DEVHOME)\customize\resources\myerrormsg_ja.properties.UTF8 に「キー=値」形式のメッセージを記述します。 次のコードでロケールに対応した適切なメッセージが出力されます。(この例では、キーに "error.original" という名称を使っています。)

p.errors.addJfcerror(errorManager.getJfcerror("error.original", p.locale));

エラーメッセージファイルにプレースホルダを指定することもできます。具体的には次のようになります。

var arrayOfStrings = Java.type("java.lang.String[]");
var obj = new arrayOfStrings(1);
obj[0] = "テストです。";
p.errors.addJfcerror(errorManager.getJfcerror("error.original", obj, p.locale));
Java 6/7 利用時は、配列の扱いが異なります。詳細は「Java 6/7 利用時の注意点 > 配列の扱い」をお読みください。

エラーではなく警告を使う場合は、JFCHelperUtils クラスを使います。次のようにしてください。

var JFCHelperUtils = Java.type("jp.jasminesoft.jfc.JFCHelperUtils");

var s = model1.item1;
if (s != null && s == '(エラーとしたい値)') {
    var warn = new Jfcwarn();
    warn.content="..."; /*警告メッセージ*/
    JFCHelperUtils.checkWarnedError(
        p, s, warn, "model1.item1", 
        "model1.item1.error.input.generic");
}

JFCHelperUtils.checkWarnedErrorメソッドの第一引数は p となります。第二引数は「入力された値」です。第三引数は警告オブジェクト(warn)です。第四引数は「モデルID.項目ID」としてください。第五引数は国際化対応時、エラーメッセージのリソースのキー名となります。通常は「モデルID.項目ID.error.input.generic」としてください。

Webフォームからの入力ではなく、自動計算によって求められた値を使った「整合性チェック」を行うこともできます。この場合はストアモデルを用います。ストアモデルは画面から入力された文字列を適切な型(文字、数字、日付)に変換した値を保持します。また自動計算によって求められた値も保持します。

次の例は、親モデル Parent と子モデル Child (外部キーで関連する親子関係)において、親側の Parent に、子である Child モデルの数(COUNT)および、項目の最大値(MAX)が定義されているものとします。

具体的には Parent モデルの countOfChild 項目には計算式「COUNT(${child_lp})」が、maxOfChildItem1 項目には計算式「MAX(${child_lp.item1})」が、それぞれ定義されているものとします。

このとき、countOfChild 項目は2以上、maxOfChildItem1 項目が100以上というルールは次のように記述します。

/* Parent はストアモデル */
if (Parent.countOfChild < 2) {
    var error = new Jfcerror();
    error.content = "子モデルの数は2以上です。";
    p.errors.addJfcerror(error);
}
if (Parent.maxOfChildItem1 < 100) {
    var error = new Jfcerror();
    error.content = "子モデルitem1の最大値は100以上です。";
    p.errors.addJfcerror(error);
}
上記コードでもし Parent_p と表記すると、プレゼンテーションモデルを用います。プレゼンテーションモデルは画面から入力された値(文字列)を保持しますが、countOfChild 項目は計算式なので値が入っていません。よって、ここでプレゼンテーションモデルを用いるのは不適切、となります。

親子モデル関係において、子モデルの同時更新を有効にします。

このとき「親モデルに、必ず1件以上の子モデルが必要」という入力チェックは次のように記述できます。子モデルを Child と定義しています。

/* 子モデル名を Child と定義している */
var Child_ary = p.request.getAttribute("Child_ary");/*子モデル配列の取得*/
var count = Child_ary.length;
if (count < 1) {
    var error = new Jfcerror();
    error.content = "子モデルChildは1件以上、必要です。";
    p.errors.addJfcerror(error);
}

親子モデル同時更新機能では、入力チェック処理のタイミングで、対象となる子モデルの配列が、p.requestオブジェクトに格納されています。キー名は「子モデル名_ary」です。末尾に "_ary" をつけたキー名で、配列を取得できます。

これを取得し、配列の数をチェックすることで、子モデルの数を知ることができます。

なお、ここで取得した Child_ary はストアモデルです。

この例では Child の先頭は大文字となっています。モデル名が child と先頭が小文字の場合は、p.request.getAttribute("child_ary") となります。

親子モデル関係において、子モデルの同時更新を有効にします。

このとき「親モデルの出荷日と、各子モデルの納期日を比較する」というスクリプトを次のように記述することができます。

/*親モデルの出荷日と、子モデルの納期を比較する*/
var syukkabi = Parent.sdate;/*Parentはストアモデル*/
var Child_ary = p.request.getAttribute("Child_ary");
var count = Child_ary.length;
for (var i=0; i<count; i++) {
    var Child = Child_ary[i];/*Childもストアモデル*/
    var nouki = Child.nouki;/*syukkabiもnoukiもJavaScriptのDate型オブジェクトとして扱える*/
    if (syukkabi.getTime() > nouki.getTime()) {
        var error = new Jfcerror();
        error.content = (i+1)+"番目の納期は、出荷日よりも早い日になっています。";
        p.errors.addJfcerror(error);
    }
}

Parent ならびに Child_ary はストアモデルです。ストアモデルは文字列、数字、日付型を区別しているため、項目 sdate や nouki は日付型と認識されます。そのため JavaScript の日付オブジェクトとして操作できます。具体的には getTime() メソッドを利用した比較処理を行うことができます。

この例では Child の先頭は大文字となっています。モデル名が child と先頭が小文字の場合は、p.request.getAttribute("child_ary") となります。

customer モデルが最大、10件までしか登録できない、というルールを想定します。このチェックのためには現在、データベースに格納されている「件数」を知る必要があります。

入力チェックのスクリプトでデータベースを操作するためには、開発者の方で「セッション」を取得します。

トランザクションスクリプトでは、すでにあるセッションを使うことができますが、入力チェック処理はデータベース操作を伴わないことから、開発者が自らでセッションを取得します。

実行タイミング「入力チェック」に次のスクリプトを記述します。

var HibernateUtil = Java.type("jp.jasminesoft.jfc.app.HibernateUtil");
var session = HibernateUtil.openSession();
try {
    var o = session.createSQLQuery(
           "SELECT COUNT(*) FROM \"customer\"").uniqueResult();
    if (o > 10) {
        var error = new Jfcerror();
        error.content = "10件以上のデータを登録することはできません。";
        p.errors.addJfcerror(error);
    }
} catch (e) {
    e.printStackTrace();
} finally {
    if (session !== null) {
        session.close();
    }
}
  • データベース操作のためのセッションオブジェクトは HibernateUtil.openSession() を使って取得します。
  • 取得したセッションは必ずクローズしてください。クローズを忘れると、利用できるデータベースセッションが不足し、運用途中で実行時エラーになります。
  • 上のスクリプトではテーブル customer の前後をダブルクォートで囲っています。お使いのデータベースによって、シングルクォートまたはダブルクォートのどちらかを使います。(内蔵DBであるHSQLDB利用時は、二重引用符で囲みます。)このため、開発機と本番機で異なるデータベースを用いる場合は、スクリプトファイルの変更も行う必要があるかも知れないということにご留意ください。
  • SQLは検索系でのみ利用してください。(Wagbyは更新時に独自のロックマネージャを使います。それを無視して直接、SQLで更新するとデータの整合性を保証できなくなります。)
  • 上記のサンプルコードは uniqueResult メソッドを使っているため、戻り値は常に1件である必要があります。複数件のレコードを返す SQL を記述した場合は list メソッドを使うことができます。詳細は Hibernate プログラミングの学習が必要となりますので、ここでは割愛します。(なお、複数件を扱う場合は、SQL ではなく Wagby が提供する EntityService を使うこともご検討ください。)

一覧更新画面に用意された「入力チェック」でスクリプトを呼び出します。値の変更があった行の数だけが対象となります。(変更せずに「入力チェック」ボタンを押下してもスクリプトは呼び出されません。)

図2 一覧更新画面の入力チェック

「スクリプト > ヘルパ > 入力チェック(一覧更新)」を用意します。例を示します。

stdout.println("入力チェック "+customer+" "+customer_ulp);

if (customer.customername == "aaa") {
    var error = new Jfcerror();
    error.content = "顧客名に aaa は利用できません。";
    p.errors.addJfcerror(error);
    return error.content;
}

スクリプト内ではストアモデルの他、一覧更新画面でのみ利用できる、接尾語に "_ulp" が付与されたプレゼンテーションモデルを参照することができます。

ここで値を書き換えることはできません。入力チェックスクリプトのため、値の参照のみを行ってください。