では、実際にコーディングしてみます。必要に応じて、Paraselene API を参照して下さい。
生成されたスケルトンソースファイルは以下のようになっています。
| 1 | tutorial1/Gate.java | サーブレット本体です。 web.xmlには、*.na の URL を Gate クラスで処理するよう指定されています。 |
| 2 | tutorial1/DummyPage.java | URL に遷移元ページが無い場合に処理されるクラスです。 |
| 3 | tutorial1/SuperPage.java | logic ディレクトリ下全てのクラスの親クラスです。 共通ルーチンを設けたい場合に使用します。 例えば、共通のエラーチェックがある、全ページ共通のヘッダやフッタを生成したい場合等がそれにあたります。 |
| 4 | tutorial1/Json.java | 非同期通信を行うためのクラスです。このチュートリアルでは説明しません。 ※-json true を指定した場合のみ生成されます。 |
| 5 | tutorial1/logic/LoginHtml.java | ログイン画面のロジックを記述します。 |
| 6 | tutorial1/logic/HelloHtml.java | Hello 画面のロジックを記述します。 |
| 7 | tutorial1/view/LoginHtml.java | 開発者はこの中のソースを変更しないで下さい。 view ディレクトリのクラスは logic クラス直接の親クラスで、logic クラスと同じ数だけ存在します。 ここにあるソースは、モックアップ HTML をそのまま再現するための初期化ルーチンを持っています。 1度スケルトンを生成した後に HTML を変更し、再度スケルトンを生成しなおすと、このソースが新しく置き換わり、logic 側は変更されません。 |
| 8 | tutorial1/view/HelloHtml.java | 同上。 |
| 9 | tutorial1/base/PageType.java | 開発者はこのソースを変更しないで下さい。 各ページには PageID が設定され、プログラム中でページを指定する際には PageID を使用します。 このクラスはその定義を持ちます。その実体は Enum クラスです。 |
| 10 | tutorial1/base/PageLoader.java | 開発者はこのソースを変更しないで下さい。 Paraselene へ、tutorial1 で定義された各ページクラスインスタンスを提供する役目を持ちます。 このクラスはスレッド化され、バックグラウンドでページインスタンスを作り置きしています。 サイト利用者のアクセスに先行して、各ページインスタンスは既に複数個立ち上がり処理を待っている状態になっています。 |
| 11 | tutorial1/base/Json.java | 開発者はこのソースを変更しないで下さい。 非同期通信を行うためのクラスです。このチュートリアルでは説明しません。 ※-json true を指定した場合のみ生成されます。 |
これらにjavadocを通せば、どのようなメソッドを持っているか把握しやすくなります。
tutorial1/logic/LoginHtml.java の内容を見てみます。基本的に HelloHtml.java も同じ内容です。
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77:
package tutorial1.logic; import tutorial1.*; import tutorial1.base.*; import paraselene.*; import paraselene.supervisor.*; import paraselene.tag.*; import paraselene.tag.attr.*; import paraselene.tag.form.*; import paraselene.tag.list.*; import paraselene.tag.table.*; /** * login.html */ public class LoginHtml extends tutorial1.view.LoginHtml { /** * コンストラクタ。 */ public LoginHtml() { super(); init(); } /** * 初期化。 */ public void init(){ super.init(); // モックアップHTMLの内容と異なる内容で初期化したい場合は // super.init()の後に変更用の処理を記述して下さい。 // このメソッドは上記コンストラクタの中から呼ばれます。 // インスタンス発生はバックグラウンドで非同期に処理していますので // HTTPリクエスト発生よりずっと過去に初期化されます。 // このため、ユーザーのトランザクションに応じた条件分岐を設けても // 意図した振る舞いになりません。 } /** * 別名URI設定。nullを返すと別名は設定しません。 * 最低4文字指定して下さい。 * ".na"で終えると完全一致となりますが、".na"で無ければ先頭一致となります。 * @return URI。 */ public String getAliasURI() { return null; } /** * 入力値の検証を行う。 * このメソッドが呼ばれる際には必ずセッションが発生しています。 * 入力値のエラーチェックや入力値に即した動作を記述します。 * @param req リクエスト内容。 * @param fw デフォルト遷移先。 * @exception PageException 処理の継続が不可能(ブラウザには500を返す)。 */ public Forward inputMain( RequestParameter req, Forward fw ) throws PageException { // fwにはモックアップと同じ遷移先が設定されています。 // 別の遷移先としたい場合は、新しくForwardインスタンスを生成して // リターンして下さい。 return fw; } /** * 出力情報の設定を行う。 * @param from 遷移元ページ。直接呼ばれている場合はnullです。 * @param req リクエスト内容。 * @return 出力ページ。 * nullを返すとthisをリターンしたのと同じ扱いにされます。 * @exception PageException 処理の継続が不可能(ブラウザには500を返す)。 */ public Page outputMain( Page from, RequestParameter req ) throws PageException { // 出力内容を設定します。 // 初期化したい場合は、init()をコールして下さい。 return this; } }
このうち、主な変更箇所は inputMain() と outputMain() になります。
例えば、ブラウザにはログイン画面が表示されており、この時ログインボタンを押下すると以下のように処理がなされます。
この処理フローを念頭にコーディングを行っていきます。
では、このサイトの動作仕様を以下のようにします。
では、順番にコーディングしていきます。
ログイン画面は、login.naでアクセス可能とする。 getAliasURI メソッドを以下のように変更します。
これでブラウザから、http://localhost:8080/tutorial1/login.na でアクセスできるようになりました。
ログイン画面からログインする時、ユーザーIDとパスワードは必須入力項目とする。 ユーザーIDは何でも良い事とし、パスワード"pass"であればログインできるようにする。 ログインエラーであれば、error.htmlへ遷移する。
まず、自分自身のページに何が入力されたかを知る方法からです。
tutorial1.view.LoginHtml(今修正中の tutorial1.logic.LoginHtml の親クラス)には、以下のメソッドがあります。
| 1 | nameが"user_id"であるテキストボックスを得る。 | |
| 2 | public paraselene.tag.Tag[] getUserIdTags() | |
| 3 | nameが"password"であるテキストボックスを得る。 | |
| 4 | public paraselene.tag.Tag[] getPasswordTags() |
スケルトン生成ツールは、以下の規則でメソッドを命名します。
get name設定値 タグの種類
1番であれば、UserId が "user_id" より、そして <INPUT> タグであるのでこの名称となっています。
このように、name が設定されたタグには全て、アクセッサが準備されます。
例えば、getUserIdInput のソースは、以下のように書かれています。
1: 2: 3:
public paraselene.tag.form.SingleTextBox getUserIdInput() { return (paraselene.tag.form.SingleTextBox)getTag( "user_id" ); }
getTag( name 設定値 )により、同じ事が出来る事が分かります。
ただし通常は、getTag を直接呼ばず、getUserIdInput を使って下さい。
もしモックアップ HTML で "user_id" を "user_name" に変更しツールを通すと、getUserIdInput が消滅し、代わりに getUserNameInput が作られます。
このままコンパイルすると、getUserIdInputを使っている箇所でコンパイルエラーが発生します。
もし getTag("user_id") としていたら、実行時に Exception が発生するまでデザインが変更された事に気付かないかもしれません。
それでは、実際に LoginHtml の inputMain を書いてみます。
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
public Forward inputMain( RequestParameter req, Forward fw ) throws PageException { // fwにはモックアップと同じ遷移先が設定されています。 // 別の遷移先としたい場合は、新しくForwardインスタンスを生成して // リターンして下さい。 try { // 未入力チェック。 Control.checkNull( null, getUserIdInput(), getPasswordInput() ); // パスワード検証。 if ( !getPasswordInput().getValueString().equals( "pass" ) ) { throw new ControlException( null, (Control)null ); } } catch( ControlException ce ) { try { // error.htmlへ遷移させる。 return new Forward( new java.net.URI( "error.html" ), false ); } catch( java.net.URISyntaxException uri_e ) { // 例外発生により続行不能。 throw new PageException( uri_e ); } } return fw; }
入力エラーはこのように、ControlExceptionをキャッチした箇所でハンドリングすればよいでしょう。
error.html へ遷移させるには、Foward を new してリターンする事で行います。
また、 URI クラスコンストラクタは URISyntaxException をスローします。もしこれが発生すれば処理を続行できないので、 PageException をスローして処理を中断します。
error.html はそのままでは "login.html" へリンクしているので、修正しておきます。
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Style-Type" content="text/css"> <title></title> </head> <body> <p>ログインできません。</p> <p><a href="login.na">戻る</a></p> </body> </html>
最後に、HelloHtml の outputMain を修正します。
1: 2: 3: 4: 5: 6: 7:
public Page outputMain( Page from, RequestParameter req ) throws PageException { // 出力内容を設定します。 // 初期化したい場合は、init()をコールして下さい。 LoginHtml login = (LoginHtml)from; this.getUserIdSpan().setValueString( login.getUserIdInput().getValueString() ); return this; }
from のインスタンスは、ログイン処理を行った LoginHtml インスタンスです。
そこからユーザーIDを取得します。
この時、ログイン画面のユーザーIDにと入力すると、Hello 画面には
こんにちは>テスト"さん。
と表示されます。
getValueString は、コントロール系のタグであれば value 属性を、そうでなければタグで囲まれた文字列を取得します。
setValueString も同様に上記の位置に文字列を設定します。
また上の入力例のように、Paraselene がエスケープ処理を行いますので、プログラム側は">テスト\""という文字列として扱えます。
例えばから getValueString すると、改行は"\n"に見えます。
それを<SPAN>へ setValueString を行うと、
1行目<BR>
2行目
と設定されます。