logo

サイト内検索
ココログ最強検索 by 暴想

最近のトラックバック

無料ブログはココログ

トップページ | 2009年2月 »

2008年11月

GwtExt JSONPでサーバーからデータ入手

  • ソースを表示して文中のリンクをクリックすると該当行が選択されます。
  • GwtExtの実装例ですが、ext.jsでも同じ考えで行けると思います。

上記ソースの表示ボタンはサーバーからソースを読み出してくる仕組みになっております。このサーバーはココログのサーバーではありません。このようにページを表示しているHTMLが存在するサーバー(正確にはドメイン)でないところからJavaScriptでAJAXなどを使用してデータを取ることは、通常はセキュリティの観点からできない事になっております。では通常でない方法でやればできるのか?というと、これを実現するのがJSONPという技な訳です。
仕組みを大雑把に言うと 

<scpript type="text/javascript" src="http://xxx.com/yy" />

というタグをHTMLに書いた場合、srcに指定したxxx.comというのはこのHTMLが配置してるサーバーと関係ないものでも許されるので、この

http://xxx.com/yy

というURLが書き出すJavaScriptから、このHTML上にあるJavaScriptの関数、たとえば

<script language="JavaScript">
<!--
function putJson(json) {
....
}
//-->
</script>

を呼び出してその引数(jsonの部分)としてデータを渡せば結果として他のサーバーのデータを読み込むことができてしまうという事です。

引き渡すデータとしては、普通JSON形式が使用されるわけです。

ext.jsにはJSONPでデータを入手するためのProxyとしてScriptTagProxyというクラスがあります。ext.jsには他にJsonStoreというStoreがあって紛らわしいのですが、こちらは同一ドメインから真っ当に?JSONデータを受け取る場合に使用するもののようです。

クライアントの実装

「クライアントソース表示」ボタンを押してソースを確認してください

		ScriptTagProxy proxy = new ScriptTagProxy(url + "/getSource?cn=" + cn);
		RecordDef recordDef = new RecordDef(
				new FieldDef[] { new StringFieldDef("row") });
		JsonReader reader = new JsonReader("rows", recordDef);

		Store store = new Store(proxy, reader);
		store.load();
		ColumnModel cm = new ColumnModel(new BaseColumnConfig[] {
				new RowNumberingColumnConfig(),
				new ColumnConfig("Source", "row", 580, false,
						new SourceRender()) });
		gp = new GridPanel(store, cm);

上記のようにサーバーの実装があるURLを指定してScriptTagProxyを生成します。このケースではリクエストパラメーターとして表示したいソースファイルのクラスネームを指定します。サーバー側にはデータを返す際に呼び出すJavaScriptの関数名(callBack関数という)も必要なのですが、これはScriptTagProxyが自動的にリクエストパラメーターに付けてくれます(defaultのパラメーター名は"callback")
RecordDefとJsonReaderを定義していますが、結論から言うとこれはrowというString属性ひとつを持ったオブジェクトの配列をrowsという名前で受け取ることを意味しています。
あとはこのScriptTagProxyとJsonReaderでStroreを作成してloadメソッドを呼ぶとリクエストがサーバーに飛びます。StroreをGridPanelにセットしておけば、callback関数が呼ばれてデータが来たタイミングでGridPanelに表示されます。

サーバーの実装

「サーバーソース表示」ボタンを押してソースを確認してください

サーバー側ではJSON形式のデータを作成するためにjson-libというライブラリーを使用しています。こちらも手っ取り早く言うとこんな形式

stcCallback1001(
    {"rows":[
        {"row":"package jp.co.kpscorp.gwt.client;"},
        {"row":""},
        {"row":"import java.util.ArrayList;"},
          途中省略
        {"row":"}"}
    ]}
)

の文字列を返すようにすればよい。上記の意味はstcCallback1001というJavaScript関数をJSONオブジェクトを引数として呼び出しているわけです。JSONオブジェクトはrowというひとつのString属性(中身はソースの1行)をもつ配列にrowsという名前を付けたものです。stcCallback1001はcallback関数の名前でScriptTagProxyがリクエストパラメーターに付けて渡してきたものです。

json-libによるJSONオブジェクトの作成


		List l = new ArrayList();
		while ((line = br.readLine()) != null) {
			Map map = new HashMap();
			map.put("row", line);
			l.add(map);
		}

上記のように"row"というキーに対して1行分の文字列をputしたマップのリストをjson-libに渡して

		JSONArray jsonArray = JSONArray.fromObject(l);

とやるだけでJSONの配列が出来ます。この際の注意点は、JSONは基本的にutf-8で作るという規約になっているようなので、ファイルを読む際に

		InputStreamReader in = new InputStreamReader(fis, "UTF-8");

このようにエンコードUTF-8で読んでレスポンスのContentTypeも以下のようにUTF-8指定にします。

		res.setContentType("application/json; charset=UTF-8");

以上。

HTML上のJavaScriptからGWTのJavaコードの呼び出し

  • ソースを表示して文中のリンクをクリックすると該当行が選択されます。

GWTにはJSNIという機能があってJavascript-Java間を入ったり来たりできるわけです。しかし、GWTのソース上に書いたJavaScriptのnativeコードとJavaコードのやり取りではなく、HTMLソース上に書いたJavaScriptからGWTのJavaコードを呼び出す方法に関してはあまり資料が無いようなのここに記述します。

上記ソースはこのソースコードを表示する機能自体のソース(ややこしい)ですが、ブログ文書のリンクから特定の行をフォーカスする機能を持っています。例えばここをクリックすると10行目をフォーカスします。この場合のHTMLのソースは、

    <a href="#" onclick="selLine('10');return false;">ここ</a>

というselLine()というJavaScript関数を呼び出すアンカータグになっています。ちなみにアンカータグなのでhrefのurlにこのままだと飛んでいこうとしますので、falseをreturnしてそれを抑止しています。

このselLine関数が実はGWTのJavaコードにつながるわけですが、そこ仕込んでいるのは、以下の部分です。

	private native static void setup() /*-{
	 $wnd.selLine = function(lines) { @jp.co.kpscorp.gwt.client.SourceButton::sel(Ljava/lang/String;)(lines);}
	 }-*/;

$wndはGWTのnativeコード内で使用できるWindowオブジェクトの参照なので
$wnd.selLine = function(lines) { ・・・・・}
とやるとこのWindowにsetLineというfunctionを定義したことになります。中身はGWTのJavaコードSourceButtonクラスのstaticメソッドselを呼び出す事を意味しています。(JSNIのお約束:詳しくはココを参照)。上記setupメソッドをあらかじめ呼んでおくことで、selLineという関数が有効になり、HTML側から呼ぶことが出来るようになります。

SourceButtonクラスのstaticメソッドselはJavaで書かれたコードで該当の行を選択します。その件はココに書いたとおり。

Gwt Ext 特定のHTMLエレメントの属性を調整する

  • ソースを表示して文中のリンクをクリックすると該当行が選択されます。
  • GwtExtの実装例ですが、ext.jsでも同じ考えで行けると思います。

CSS selectorの話題が出たところでGwtで特定のHTMLエレメントの属性を調整する技について少し。
GWTのapiやext.jsのコンフィグオプションなどだけでHTMLの細かい属性をすべて設定するのは無理なようで、たとえば<div>等に指定するalign属性は、api等ではあちこち探したが設定する方法が無い。たとえば、上記「ソース表示」ボタンを押して出るWindowですが、これがほって置くとblogで指定されたalignがcenterなので文字が真ん中によってでます。↓
Untitled
上記画像をクリックしてみてもらえばわかるようにソースを見るのには非常に悲しい状態になります。
これのalignをleftにするには上位のタグのどこかでalign=leftとしてやればよいのだが、ext.jsのWindowにalignを調整する機能は見当たらない。少々悩んだが、こうなりゃDOMのapiでやっちまえ、ということで以下のように(113)しました。

        DOM.setElementProperty(w.getElement(), "align", "left");

単純にWindowのエレメントを取ってきてプロパティをセットするだけです。

GwtExt Gridの特定行までスクロールする

の記事にも書いた CSS selectorを使用すれば生成されるHTMLの特定のエレメントを捕まえることができるので、あとはDOM.setElementPropertyとやってしまえば、なんでもありということです。(多分)

GwtExt Gridの特定行までスクロールする

  • ソースを表示して文中のリンクをクリックすると該当行が選択されます。
  • GwtExtの実装例ですが、ext.jsでも同じ考えで行けると思います。
     

スクロール可能なGridの場合、表示されるたびにスクロール位置が最初に戻って不便だったりしませんか?
上記でも使用している「ソースの表示」機能で、ある特定のまでプログラムからスクロールさせる方法実装しましたので紹介します。

上記「ソースの表示」ボタンを押すと現れるソースはこのソースの表示機能自体を実現しているソースです。この中で特定行までスクロールする機能の部分は以下のところ(170-185)

// スクロール位置調整
Element[] es = Ext.get(gp.getId()).query(
		"*[class*=x-grid3-row-table]");
Element con = Ext.get(gp.getId()).child(
		"*[class*=x-grid3-scroller]");
int p = is[0];
if (p > 2) {
	p = p - 2;
}
int ep = is[is.length - 1];
if (ep < es.length - 3) {
	ep = ep + 2;
}
w.setPosition(w.getPosition()[0], Ext.getDoc().getScroll()[1]);
new ExtElement(es[p]).scrollIntoView(con, true);
new ExtElement(es[ep]).scrollIntoView(con, true);

Gridの各行はx-grid3-row-tableというCSSのクラスが設定されているので、170-172のようにExtElementのqueryメソッドを発行するとGrid gpの配下の該当のCSSが設定されているElementの配列が取れます。つまりこれが、全行の配列になります。一方、int配列isに選択すべき行番号が入っています。多少上下に余裕を持ったところに位置づけたいので前後2行ずつ足し引きしてスクロール範囲に入れたい範囲の上限行と下限行をp,epに得ます。
実際に、スクロールするのは184-185。conはExtElementのchildメソッドでスクロールをしているコンテナのエレメントを捕まえたものです。scrollIntoViewメソッドでconの中のes[p]とes[ep]を表示エリアに出せ!とやって出来上がりです。
なお183は現在のブラウザー自体の縦スクロール位置にソースのWindowを持ってくる処理です。Ext.getDoc().getScroll()で現在のブラウザー自体のスクロール位置が取れるので、縦方向のみそこに位置づけしております。

ちなみに、queryやchildメソッドで引数にしている

"*[class*=x-grid3-scroller]"

という文字列はCSS selectorというもので、HTML上の特定のエレメントを捕まえるための文法でたとえばこの辺↓
http://pigs.sourceforge.jp/wiki/index.php?CSS%2Fselector

に説明があります。

ココログへフォルダーごと一括アップロードする

ココログ上でGWTを動かすことを試みていた関係で、ファイルの一括アップロードは避けて通れない課題でありました。あちこち探してうまい方法が見つからなかったのですが、観測気球さんのブログで

ココログの任意のディレクトリにファイルをアップロードするツール

というのを発見。
これで、コマンドラインからアップロード機能を起動することが可能なので、以下のようなバッチファイルを作成しました。

for %%f in ( %1 ) do "C:\Program Files\uploadFile139\uploadFile.exe" -u ユーザーID -Pパスワード -f %%f -d %2 -t

上記の1行をメモ帳貼り付け ユーザーID と パスワードのところを自分のブログのものに変えて cocoup.bat という名前で保存します。(C:\Program Files\uploadFile139\uploadFile.exeのところは、観測気球さんのところからダウンロードしたuploadFile.exeの場所を示します)
このバッチファイルをコマンドラインから以下のように起動します。

cocoup  送信元ファイルセット  送信先のフォルダー名
例: cocoup C:\www\*.* gwt

上記の例ではPC上のC:\wwwのすべてのファイルを自分のココログのgwtのフォルダーに送信します。

非常に便利で感謝しております。

GwtExt FormPanelとGridの連携

  • ソースを表示して文中のリンクをクリックすると該当行が選択されます。
  • GwtExtの実装例ですが、ext.jsでも同じ考えで行けると思います。

Untitled

FormPanelからgetForm().loadRecord(record)を実行することで、Grid上の特定のレコードの内容をFormPanelに簡単に表示することができます。
http://www.gwt-ext.com/demo/#formGridにサンプルコードが掲載されているが、このケースはGrid→FormPanelは実装されているが、フォーム上で編集した内容をGrid側のデータに書き戻す部分が無かったのでそこを追加実装した例を示します。

前準備

Gridで使用しているStoreにFieldDefの配列をセットする(206-210)。ここで指定した文字列がFieldのカラム名になる。
    private static RecordDef recordDef = new RecordDef(new FieldDef[] {
            new StringFieldDef("company"), new FloatFieldDef("price"),
            new FloatFieldDef("change"), new FloatFieldDef("pctChange"),
            new DateFieldDef("lastChanged", "n/j h:ia"),
            new StringFieldDef("symbol"), new StringFieldDef("industry") });

FormPanelにのせるTextFieldのオブジェクト生成時に上記カラム名と一致したnameを付ける。(89-95)この例ではコンストラクターの2つ目の引数がnameになる。

        // the field names msut match the data field values from the Store
        fieldSet.add(new TextField("Name", "company", 120));
        TextField priceField = new TextField("Price", "price", 120);
        fieldSet.add(priceField);
        TextField pctChangeField = new TextField("% Change", "pctChange", 120);
        fieldSet.add(pctChangeField);
        fieldSet.add(new DateField2("Last Updated", "lastChanged", 120));

GridからFormPanelへ連携

まず、Grid→FormPanelの反映する部分をおさらいすると、以下の部分(49-62)

        final RowSelectionModel sm = new RowSelectionModel(true);
        sm.addListener(new RowSelectionListenerAdapter() {
            public void onRowSelect(RowSelectionModel sm, int rowIndex,
                    Record record) {
                formPanel.getForm().loadRecord(record);
            }
        });

行をGridから選択した際、RowSelectionModelのonRowSelectアクションで選択されたrecordが入手できるので、これをformPanel.getForm().loadRecord(record)とやるだけでOK。

FormPanelからGridへ連携(121-137)

逆の連携は少々手間がかかる。まず、FormPanel上のすべてのFieldのonChangeイベントを拾うListenerを仕込んでおいて、Fieldの変更時に該当のRecord側に値を設定する。

    private void setFieldListeners(FormPanel fp, final RowSelectionModel sm) {
        // FormPanel上のすべてのFieldにChangeイベントを拾うListenerを追加
        Field[] fds = fp.getFields();
        for (int i = 0; i < fds.length; i++) {
            Field fd = fds[i];
            fd.addListener(new FieldListenerAdapter() {
                public void onChange(Field field, Object newVal, Object oldVal) {
                    // Fieldの値変更時にRecordへ反映
                    Record record = sm.getSelected();
                    if (!(record.getAsString(field.getName()).equals(newVal))) {
                        setAsString(SampleGrid.recordDef, record, field);
                    }
                }
            });
        }
    }

ここで注意!

上記Listenerの設定は、RootPanel.get().add(panel);でFormPanelがrender(表示)された後でないと有効にならないようだ。だから、以下のように(115-117)最後に行う。

        RootPanel.get().add(panel);
        setFieldListeners(formPanel, gridPanel.getSelectionModel());

値の設定(139-159)はRecord定義時のRecordDefから型を判断してセットする。FloatFieldDefの場合はdoubleへの変換。DateFieldDefの場合はDateFieldのgetDateでDateオブジェクトを取る。

    private void setAsString(RecordDef def, Record record, Field field) {
        if (!field.validate()) {
            return false;;
        }
        FieldDef[] fdefs = def.getFields();
        for (int i = 0; i < fdefs.length; i++) {
            FieldDef fdef = fdefs[i];
            String id = field.getName();
            if (fdef.getName().equals(id)) {
                if (fdef instanceof FloatFieldDef) {
                    record.set(id, new Double(field.getValueAsString())
                            .doubleValue());
                } else if (fdef instanceof DateFieldDef) {
                    DateField df = (DateField) field;
                    record.set(id, df.getValue());
                } else {
                    record.set(id, field.getValueAsString());
                }
            }
        }
    }

さて、これでOKと思ったのだが、このまま動かすとFieldを編集した直後にGridをクリックして直接他の行に選択を移したケースで変更が反映されない事が判明。デバッグした結果、なぜかonRowSelectイベントがFieldのonChangeよりも前に呼ばれる事が原因だった。onRowSelectで新たに選択した行のrecordでFieldを上書きしてしまうので、編集したデータが失われる(onChangeをonBlurにしても同じ。納得いかないが..)
仕方が無いのでonDeSelectイベントを拾って、ここでも変更されたfieldの値をrecordに反映する処理(51-62)を行う事にした。

            public void onRowDeselect(RowSelectionModel sm, int rowIndex,
                    Record record) {
                // 行の選択が解除された時の処理
                // 変更されたfieldの値をrecordに反映
                Field[] fs = formPanel.getFields();
                for (int i = 0; i < fs.length; i++) {
                    Field field = fs[i];
                    if (field.isDirty()) {
                        setAsString(SampleGrid.recordDef, record, field);
                    }
                }
            }

入力チェックの実装

priceとpctChangeはdoubleに変換する都合上変な値を入力されると困るので、入力チェックを実装しましょう。正規表現を使用して以下のようにsetRegexに正規表現をしていすればOK。なお、この機能は内部的にRegExp.test()メソッドでチェックをしているので、regexの最初と最後にちゃんと^と$を入れないとザル状態になりますので注意。(そうしないと正規表現に一致する部分がどこかにあればOKになってしまう。これで少々ハマッタ)

        // 正規表現とalowblankによる入力チェック
        String regex = "^[-+]?[0-9]+(\\.[0-9]*)?$";
        String regexText = "数値が無効です";
        String blankText = "空白には出来ません";
        priceField.setRegex(regex);
        priceField.setRegexText(regexText);
        priceField.setAllowBlank(false);
        priceField.setBlankText(blankText);
        pctChangeField.setRegex(regex);
        pctChangeField.setRegexText(regexText);
        pctChangeField.setAllowBlank(false);
        pctChangeField.setBlankText(blankText);

なおsetAllowBlank(false)は空白値を許さない設定です。

Test

GWTのTest

このページはGWTのテスト用のページで意味はありません。

特定のHTMLタグに同じCSSを設定する

CSSリファレンス

特定のHTMLタグに同じCSSを設定する

HTMLタグの中で、「Class」「id」を指定して使うのが定番のCSSですが、
特定のHTMLタグだけに設定をする方法があります。

一般的な使い方は、importしたCSSファイルの中で以下の様に記述します。
INPUT{width: 100px;} や DIV{border:1px solid #ff0000;} です。

この場合はCSSファイルをimportしている全てのHTMLタグに適用される為、
画面共通の部品の場合には便利ですが、特定のページだけ・特定の場所だけ
という場合には使えなくなります。

そこで、「Class」「id」を指定したHTMLタグの中にある部品に設定する方法があります。
.aaa INPUT{width: 100px;} や .aaa DIV{border: 1px solid #ff0000;} です。
通常のCSS設定名の後ろに半角スペースを空けてHTMLタグ名を記述します。

以上の2点だけで、CSSの汎用性が大きく上がり、使い勝手が良くなります。

Hibernate関連

Hibernate関連

select時にTransientObjectException

net.sf.hibernate.TransientObjectException:
  object references an unsaved transient instance - save the transient instance before flushing:
  jp.co.kpscorp.KihonChkMente.gwt.server.model.NenkiTbl/cause=null

 

原因
meny-to-oneのone側のオブジェクトをnewしてcriteriaの条件に指定しているが、そのオブジェクトのtimestampの項目がセットされていない。
対策
meny-to-oneのone側のオブジェクトをcriteriaの条件にしてする場合はnewするのではなくDBから読んだオブジェクトを使用する

postgresql関連

postgresql関連

使用しようとしているリソースが他からlockされて、処理が動かない

対策
psコマンドで稼動中のプロセスを調べる

   ps aux


「idol in transaction」等の表示で止まっているプロセスを特権ユーザーからkillする

   su
   rootのパスワード入力
   kill プロセス番号

Tomcat関連

Tomcat関連

Tomcatの起動がかなり遅くなる。

原因
javaのソースの中でデバックポイントをおいた所がコメントアウトになっている。
対策
デバックをはずせば問題なしです。

Tomcat単独では起動できるのに、EclipseのTomcatプラグインからは起動できない

メッセージ:
   致命的:Begin event threw exception
      java.lang.ClassNotFoundException: org.apache.catarina.core.StanderdServer

原因
Tomcat単独で起動できるのに、Eclipseからは起動できないのは、CLASSPATHが多すぎる場合とか、既に起動させている場合に発生する。(だったらClassNotFoundExceptionじゃないよ!)
対策
『[設定]-[Tomcat]でJavaプロジェクトをTomcatのクラスパスに追加する』にチェックしていないか確認する。

致命的:Perse Error at line xx column xx:と表示されるが、Tomcatは起動する。

メッセージ:
    致命的:Perse Error at line xx column xx:
      The content of element type "web-xml" must match"(icon?,……,ejb-localref*)".

原因
xml(この場合web-xml)記述の出現順序が指定順序になっていない。
対策
要素の種類毎に並べる必要がある。この順序は(エラーに表示されているが)DTDに定義されている。

「web-app_2_3.dtd」を見ると

<!ELEMENT web-app (icon?, display-name?, description?, distributable?,
context-param*, filter*, filter-mapping*, listener*, servlet*,
servlet-mapping*, session-config?, mime-mapping*, welcome-file-list?,
error-page*, taglib*, resource-env-ref*, resource-ref*, security-constraint*,
login-config?, security-role*, env-entry*, ejb-ref*,  ejb-local-ref*)>

となっている。このときは「servlet*,とservlet-mapping*,」が混在していた。



JSPの表示で"~"が"?"に文字化けする。

原因1
J2SDK1.4.1以上からcharsetの解釈が変わり、pageディレクティブにcharset=Shift_JISとすると文字化けが一部の文字に起こる。
対処方法1.1
JSPのcharset指定を以下のようにMS932にする。

server/ <%@ page contentType="text/html;charset=MS932" buffer="64kb" %>

対処方法1.2
tomcatのサンプルで提供されているSetCharacterEncodingFilterを使用し、web.xmlにて以下のようなパラメーターを設定する。

<filter>
    <filter-name>Set Character Encoding</filter-name>
    <filter-class>filters.SetCharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>MS932</param-value>
    </init-param>
</filter>

追記
MS932指定によって解消される文字化けは、「~∥-¢£¬」や機種依存文字(①、㈱、№、Ⅱなど)ですが、Oracle使用時は「~」の文字化けが解消されません。

これを解決するためには、Oracleの環境変数を変えるしかないようです。

http://biz.rivus.jp/guidlines.html#p23ffa09



jstl formatタグ使用時等、response.setLocaleでlocal jaをセットすると文字化けする

原因1
Tomcatの4.1のlocaleとcharsetのディフォルトの対応がja=Shift_JISとなっているため。
対処方法
Tomcatのserver/classes/org/apache/catalina/util/にCharsetMapperDefault.propertiesを以下の内容で保存する。
ja=Windows-31J

なお、Tomcat5 (JSP 2.4)からは、web.xml内にlocale-encoding-mapping-listという指定が可能になり、ここでlocaleとcharset関係を指定可能

追記
サーバー依存なので、サーバー側設定が特定できない限り使用を控えます(西)。



JSPの日本語の表示が激しく文字化けする。

原因1
ブラウザーのエンコードの自動指定がシフトJISにならないから。
対処方法1.1
JSPに以下の指定を追加する。

<meta content="text/html; charset=Shift_JIS" http-equiv="Content-Type" />




JSPの日本語の表示が激しく文字化けする。(JSPのコンパイル時点で化けている)

原因1
TomcatのjavaEncodingの指定が無い
対処方法1.1
Tomcatのconfディレクトリーのweb.xmlに以下のservlet要素を追加

<servlet>
   <servlet-name>jsp</servlet-name>
   <servlet-class> org.apache.jasper.servlet.JspServlet </servlet-class>
      :
   <init-param>
      <param-name>javaEncoding</param-name>
      <param-value>MS932</param-value>
   </init-param>
      :
</servlet>

Struts関連

Struts関連


No getter method for property xxxx

[ServletException in:/WEB-INF/InvestNavi.jsp]
No getter method for property locGroup of bean org.apache.struts.taglib.html.BEAN'

原因1
このJSPにデータを提供するBean(ViewHelper)上にgetterが無い。(この場合property locGroupのgetterが無い)

原因2
struts-config.xmlの定義の問題。JSPのhtml:form action=に指定したPathに対応するaction要素に対応するform-bean要素にpropertyが無い。(この場合locGroupが無い)



Cannot find message resources

javax.servlet.jsp.JspException: Cannot find message resources under key org.apache.struts.action.MESSAGE

原因1
struts-config.xmlの文法エラー。

tomcat立ち上げ時のlogにSAXParseExceptionが発生していないか確認する。




does not define a handler property

javax.servlet.ServletException: DispatchMapping[/user/kagi] does not define a handler property

原因1
DispachActionを使用している場合にもかかわらず、struts-configのaction mapping上に parameter="xxxx"の指定が無い。



No input attribute for mapping path /xxxx

javax.servlet.error.message  No input attribute for mapping path /admin/role

原因1
ValidatorのチェックがNGとなったが、Action Mappingにinputの指定が無い。エラーの遷移先が決められないため。



ブラウザーの画面一杯にValidatorのJavaScriptが表示される。


原因1
validation.xmlのフォーム名の指定がJSP等と合っていない。



Actionクラスに制御が渡らない。


原因1
該当フォームのValidatorのチェックがNGになる条件が発生している。

対処方法1.1
Vilidation.xmlの該当フォームのチェックロジックをはずす。

対処方法1.2
ValidatorのチェックがNGにならないように対処する。



Cannot find bean hoge in any scope

javax.servlet.jsp.JspException: Cannot find bean hoge in any scope

原因1
JavaプログラムがセットしたメッセージのkeyがMessageResources.propertiesに存在しない。



does not contain handler parameter named xxxxx

Request[/user/kasidasi] does not contain handler parameter named action

原因1
DispacheActionを使用していてメソッド選択用のパラメータ(この場合action)に対応するメソッドが無い

対応1.1
選択用のパラメータに対応するメソッドをActionクラスのgetKeyMethodMap()で指定する。

原因2
linuxサーバーの場合で、URL上に指定されたリクエストパラメーターに日本語が使用されている。

↓そもそもなぜこの問題が発生するのか

「wiki.txt」

対応2.1
リクエストパラメーターを英数字にする。

対応2.2
GETメソッドの代わりに、POSTメソッドを使用してURL上にリクエストパラメーターが乗らないようにする。



Cannot find bean under name org.apache.struts.taglib.html.BEAN


原因
<html:form>タグをstrutsのタグライブラリーで記述していない



java.lang.IllegalArgumentException: No bean specified

症状
[ shohinmaker.shohinMakerCd ]のように、『オブジェクト内オブジェクトのプロパティ』をドット連結でJSPより参照する場合に、そのFormのサブミット時にExceptionが発生する場合があります。

Eclipseコンソールに表示されるException表示

javax.servlet.ServletException: BeanUtils.populate/cause=null/root cause
   =java.lang.IllegalArgumentException: No bean specified

原因1
Strutsにより、ActionFormBeanにリクエストパラメーターを設定しようとした際に、ドット連結の元オブジェクト(上記例:shohinmaker)がNULLの場合、またはそのオブジェクトのgetter自体がActionFormBeanに無い場合に発生します。

対応1-1
ドット連結の元オブジェクトをActionFormBeanのgetterから提供できるようにする。

対応1-2
ドット連結しないでデータ提供できるように、対応するプロパティのgetter、およびjspを修正する。



こちらの資料も参考になります。↓

Common Struts Errors and Causes : http://fedora/fswiki/ref/doc/CommonStrutsErrors.htm

ext.jsについて

Ext JSについて

GwtExt/ExtGWTを使うにはExt JSの知識が多少なりとも必要になります。そこでExt JSの基本的な話を少々書きます。Ext JSはAjaxアプリケーションを構築するためのJavaScriptライブラリ(フレームワーク)です。画面デザインの観点からいうと画面を構成する部品単位にすでにCSSも含めて作成済みのものが使用できることから、画面設計をより手っ取り早く行うことが出来ます。

Ext Jsの部品のサンプル
http://extjs.com/products/extjs/

コンフィグオプションによるコンポーネントの生成

Ext Jsの特徴としてコンフィグオプションがあげられます。コンポーネントの属性を設定するのに、GWTの場合は主にsetterを使用して設定しますが、Ext Jsではコンポーネント生成時にコンストラクターにコンフィグオプションという文字列(JSONだと思う)を与えることで基本的に(多分)すべての属性を決めることが出来ます。
コンフィグオプションは以下のように{}でオブジェクトひとつを表し、属性は 属性名:値 という書式になります。また配列は[]を使用します。(つまりJSON書式)
{labelWidth: 75,
   width: 350,
   title: 'FormPanel',
   layout: 'form',
   xtype: 'form',
   defaultType: 'textfield',
   buttons: [
     {text: 'Save'
     },
     {text: 'Cancel'
     }
   ],
   items: [
     {fieldLabel: 'First Name',
       name: 'first',
       allowBlank: false
     },
     {fieldLabel: 'Last Name',
       name: 'last'
     },
     {fieldLabel: 'Company',
       name: 'company'
     },
     {fieldLabel: 'Email',
       name: 'email',
       vtype: 'email'
     }
   ]
}
ここでitemsという属性はこのコンポーネントに含まれる他のコンポーネントの配列を意味します。したがってコンポーネントの入れ子になった構造もすべて一つの文字列だけですべて表現できる事を意味しています。上記コンフィグオプションは以下のような四つのtextfieldと二つのbuttonを含むFormPanelのインスタンスを生成します。

Ext01_2

xtype

xtype属性はExt Jsのコンポーネントのクラスを決定する重要な属性です。xtypeによりインスタンスのクラス自体も決定できるという事は言ってみればコンフィグオプションだけですべてを表現できる事を意味しています。xtypeとクラスの関係はExt JsのApiドキュメントのComponentの項にあります。
http://docs.ext-japan.org/docs/

layout

Panelクラスのlayout属性を設定することで様々な機能を持ったパネルのコンポーネントを作ることができます。

レイアウトの例


form layout

layout: 'form'
xtype: 'panel'またはxtype'form'
子のコンポーネントが縦に並ぶlayoutです。GWTのVerticalPanelに相当します。また、Ext.formパッケージのコンポーネントを貼り付けるにはform layoutが必要です。
xtype'form'の場合は、クラスがFormPanelとなり、submit機能等が付加されます。

column layout

layout: 'column'
xtype: 'panel'
子のコンポーネントを横に並べるlayoutです。基本的に貼り付ける各コンポーネントの位置はそれぞれのコンポーネントのcolumnWidth属性で決定します。

border layout

layout: 'border'
xtype: 'panel'
 Ext02_3

東西南北+中心のエリアを定義できるパネルです。GWTのDockPanelに相当します。しかも、オプションでボーダーをドラッグして大きさを配分を変化させる機能を付加することが出来ます。

TabPanel

layout: 'card'
xtype: 'tabpanel'
Ext03
タブによる選択を可能にするパネルです。

AcordionLayout

layout: 'acordion'
xtype: 'panel'
複数のパネルを重ねてそのうちひとつのパネルを選択可能にするレイアウトです。

GridPanel

layout: 'grid'
xtype: 'grid'
Ext04
データ表形式のパネル。元データとの連携機能も実装された強力なパネル。

TableLayout

layout: 'table'
xtype: 'panel'
Ext05
HTMLのテーブル構造を元にレイアウトできるパネルです。

トップページ | 2009年2月 »