http://quickreflector.sourceforge.net/
QuickReflector は、短期間の開発に馴染むような特徴を織り込んだフレームワークです。
短期開発に限ったことではありませんが、HTMLベースのアプリケーションを開発する際に、以下のようなことを感じる方は少なくはないと思います。
* ページデザインを随時変更したい。がプログラムの実装が入ると難しくなる。
* コメントや空白をふんだんに使って見やすいHTMLにしたい。が…
* 出力されたページに余計なコメントを残したくない。(でもソースには入れておきたい)
* プログラムとページデザインを分離して分業したい。が、これが意外と困難。
* 複数の候補を最終決定まで並存させたい。が、管理が難しい。
* ページデザインとコードの開発順序を自由に決めたい、あるいは並行で進めたい。
* プログラムに使う言語を自由に選択したい。が、特定の言語に縛られることが結構ある…
* 共通部分を作ることで省力化したい。が、かえってコストが増えたんじゃ…?
* ちょっと試したいコードがあるがいちいちページを書き換えてまた戻したりサーバの再起動をしたりというのは辛い。
* あれこれ書き換えたらページの下半分が表示されなくなった…丹念に調べたらタグの対応が崩れているのに気づくのにかなり時間を使っちゃった…orz
* せっかくeclipse のような環境があるというのにJSPだとインポート編成とかリファクタリングが使えないし、かといって Java プログラムにするとサーバの再起動が面倒だし…(Seasar2を使えばいいという話もありますが)
上記のようなことに「気持ち悪さ」を感じている方は、このフレームワークをお試しください。面白いものが見つかると思います。
このフレームワークの特徴は以下のとおり。
* HTMLページデザインにおいて…
o XHTML形式のソースを必要とする。記述ミスによりしばしば生じる壊れたHTMLはエラーとして処理される。
o ソースに余分なスクリプトレットを埋め込まないため、デザインが崩れにくい。
o デモ用のデータを配置できる。デザイン確認のときにはそれが表示されるが、アプリケーションでは出力されない。
o 共通部分を別ファイルとし、取り込むことが容易。
o や余分な空白をふんだんに使ってページを書いてよい。
o プログラム制御が必要なページにおいて、どこがプログラムであるかの識別が容易。
* プログラムによるデータの準備や表示の制御において…
o プログラム言語を特定のものだけとしない。Java はもちろんのこと、Java VM 上で動く BeanShell などの言語を容易に組み合わせて利用できる。
o プログラムを「動的」として扱うことができる。JSP のようにプログラムを書き換えると次のリクエストでコンパイルが行われる。
o リクエストやセッションの値の参照が容易に行える。
o ページ内に HTTP-HEADER を書くことができる。expire やエンコーディング指定の指定が楽に行える。
o プログラムとして組み込んではいるが部分的に起動を抑制したいような状況への対応が容易。
* アプリケーションの出力において…
o コメントや余分な空白、改行の出力レベルを調整できる。このため、出力されたページソースを”きれい”にできる。
o user-agent やユーザ条件によって同じソースから異なる出力が行われるような状況への対応が容易。
概要
QuickReflectorはHTML(XHTML)をベースとしたデザインHTMLファイルと、JAVA・各種スクリプト言語のロジックを非常にシンプルに連携させるフレームワークです。
具体的には、HTMLファイル内に、ファイルリクエスト時に実行したい各種スクリプト言語へのロジックソースファイルパスをタグで記述することで、HTMLファイルをシンプルに各ロジックと連携させることができます。
動作イメージ
TODO 動作イメージ(HTMLファイル内にタグがあり、そこからロジックに矢印)
記述例
<span ext:language="言語ID" ext:target="実行ロジックソースファイル"/>
${msg}
HTMLファイルには、このHTMLがリクエストされた時に実行するロジックソースファイルのパスを指定します。
また、SmartyやMayaaに類似した形式で変数を記述することで、値を出力したり、タグの表示・非表示を切り替えることが可能です。
さらに、クラスファイルの自動コンパイル・ロード・置換に対応しており、アプリケーションサーバーを起動したままソースファイルを更新するだけで、ほぼ全てのクラスファイルを置換することが可能です。
その結果、開発、保守時間が非常に短縮され、「クラスファイルの修正に伴うアプリケーションサーバーの再起動」が基本的に不要となります。
階層としての位置づけ
QuickReflectorは基本的にプレゼンテーション層をサポートするフレームワークです。
さらに、プレゼンテーション層に加え、クラスファイルの生存管理も行いますので、
クラスローダー管理も行うフレームワークでもあります。
TODO 図MVC階層図
開発言語選択の自由
QuickReflectorはHTMLから呼び出すロジックの言語を複数の言語から選択できます。
言語ID言語
javaJava(http://java.sun.com/)
rhinoRhino - JavaScript for Java(http://www.mozilla.org/rhino/)
beanshellBeanShell - Lightweight scripting for Java(http://www.beanshell.org/)
pnutspnuts(https://pnuts.dev.java.net/)
jythonThe Jython project(http://www.jython.org/Project/index.html)
judoscriptJudo Language(http://www.judoscript.com/judo.html)
※2008/4/30 現在
これらロジックの言語は、ext:language 指定毎に変更できますので、
ページごとに異なる言語を選択することも可能です。
今後も対応言語を増やしていく予定です。
従来の開発上の課題と解消方法
従来のWEBアプリケーション開発上の課題について、QuickReflectorがどのように解決できるか説明します。
ターゲット
課題
QuickReflectorによる解決
保守性向上
ロジックソースファイル(JAVAファイル等)を修正した場合、Tomcatを再起動する必要がある。または、オートデプロイ後、コンテキストの再起動まで時間がかかる。
そのため、結果的にメンテナンス時間が発生し、サービスを一旦停止にしなければならない。
ロジックソースファイルを更新しておくだけで、htmlへのアクセス時に自動的に更新されたロジックソースファイルをコンパイル、クラスロードし実行します。
そのためアプリケーションサーバーを停止させずにロジックの置き換えが可能です。
⇒顧客、サービス利用者にメリット大、保守コスト減少
開発時間短縮
開発中にロジックソースファイルを少し修正しただけでも、アプリケーションサーバー(コンテキスト)の再起動が必要となり、待ち時間がもったいない。
かといって、JSPベースの開発ではロジックがJSPに記述されることになり、保守・テスト・開発に支障をきたしてしまう。
ローカル開発環境でQuickReflectorベースで開発することで、ロジックソースファイルを修正してもアプリケーションサーバーを起動する必要が無いので、
非常に「サクサク」と羽が生えたような感覚の開発・動作確認スピードで進められます(体感的にはPerl,PHPと同じレベル)。
⇒開発・テスト時間短縮、開発コスト減少
開発言語選択選定の自由度
JAVAでロジックを開発したいが、jython(phyton)技術者しかいない。
初期開発は jython を利用し、状況に応じて JAVA で部分的にロジックを再構築することも可能。
⇒システムの成長・負荷状況・開発人員のスキルに合わせた言語選択が可能
デザイナーとプログラマーの分業
デザインHTMLを修正した場合、それをプログラマーがJSP等に反映させる必要がるため、プログラマーの手間が増える。
デザインHTMLに事前に一定の(ブラウザで動作確認可能な)タグを追加することで、デザインHTMLファイルをロジックから完全に分離することができ、
プログラマーがデザインHTMLをメンテナンスする必要が無くなります。
⇒デザイン修正・リリースをプログラマー等の開発者が行う必要が無くなり、完全な分業が可能
リンクについて
当サイトへのリンクはトップページ (http://quickreflector.sourceforge.net/) へお願いします。
トップよりも下のページは更新により構成が変わる可能性があります。
QuickReflectorは
QuickにWebアプリを開発し、
Quickな保守・メンテナンスを提供することで、
QuickなJAVAベースWebアプリ開発が可能、というイメージを持てる、
ことを基本コンセプトとしています。
SourceForge QuickReflector サイトより最新のモジュール、ソースコードをダウンロードしてください。
QuickReflectorを既存のTomcat用WEBアプリケーションに追加する手順を説明します。
1から設定する場合は、事前に空のWEBアプリケーションをTomcatに設定し、動作確認を行っておいてください。
※ ホスト名:localhost, コンテキストパス:sample, Tomcat起動ポート:8080 とします
SourceForgeの[Download QuickReflector]を選択し、最新のQuickReflectorをダウンロードしてください。
ロジックの言語にJAVAを利用する場合は以下のファイルをWEBアプリケーションのクラスパスにコピーしてください。
通常は WEB-INF/lib フォルダにコピーすれば認識されます。
quickreflector-silvergear-1.x.jar
quickreflector-webcore-1.x.jar
※JAVA以外の言語で開発する場合は
quickreflector-[言語名]-1.x.jar
も同様にクラスパスにコピーします。
以下の必須ライブラリをクラスパスにコピー、または追加してください。
ant.jar
ant-launch.jar
servlets.jar(Tomcat5.0以降の場合はservlet-api.jar)
環境変数 JAVA_HOME が JDK をインストールしているディレクトリを指しているか確認してください。
もし指していない場合は、以下のいずれかの方法で対応してください。
対応方法1) JAVA_HOME に JDK インストールディレクトリを指定する
対応方法2) ${JDK}/lib/tools.jar ファイルを JAVA_HOME が指しているJRE配下の lib/ext ディレクトリにコピーする
以下のservlet,servlet-mapping定義を 対象コンテキストの web.xml に追加し、JsxServlet が実行されるように設定します。
※ url-pattern による拡張子の関連付けは、任意の拡張子を指定可能です。上記の例では html,jsx と指定していますが、JsxServletが参照するファイルの拡張子は常に html です。
※ リクエスト時の拡張子に特にこだわらない場合は、url-pattern=*.html の定義のみでも問題ありません。
5.1 (Eclipseの場合) Tomcatにクラスパスを追加
EclipseのServerビューからTomcatを起動する場合は、Tomcatのクラスパスに、対象Webアプリケーションで参照する
全jarファイルを明示的に追加してください。
以上の設定で設定が完了しましたので、Tomcatを起動し動作を確認します。
Tomcatを起動し、該当コンテキストが正常起動されるかログを確認します。
正常起動されましたら、Tomcatを起動したまま以下の構成でファイルを作成します。
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
/**
*
*/
public class Index implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 1. 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// 2. メッセージを格納
container.put("msg", "Hello QuickReflector!");
}
}
※pages フォルダはQuickReflector用html,Javaファイル格納用フォルダです。WEB-INF 配下に格納する必要はありません。
※WEB-INF配下のファイルを更新すると、Tomcatの設定によっては自動的にリロードしてしまうことがあるため、pages ディレクトリは WEB-INF、ドキュメントルート以外のパスに配置されることをオススメします。
上記ファイルを配置後、ブラウザで
にアクセスし
が表示されればOKです。
C:\opt\java\tomcat5.5\webapps\sample
└─WEB-INF
│ web.xml
│
├─lib
│ ant-launcher.jar
│ ant.jar
│ quickreflector-silvergear1.0.jar
│ quickreflector-webcore-1.0.jar
│ servlet-api.jar
│
└─pages (QuickReflectorのドキュメントルート)
└─def
index.html
Index.java
※ 2008/4/30 現在では、pages 直下の java ファイルはコンパイルできません。上記の def のように何らかのフォルダ配下に作成する必要があります。
サンプルプロジェクトについて
1. ダウンロード
2. Eclipse WEB プロジェクト作成
3. WEB プロジェクトの設定
4. WEB プロジェクトの起動
QuickReflectorの開発環境を構築する際は、QuickReflectorサンプルプロジェクトを利用する素早く開発環境を構築することが可能です。
そこで、サンプルプロジェクトを利用してEclipseに動的Webプロジェクトを構築する手順を説明します。
SouceForgeダウンロード一覧ページより、最新の quickreflector-examples.zip をダウンロードして解凍します。
解凍した quickreflector-examples フォルダのフォルダ名を変更します。(仮に myqr-project とします)
さらに、Eclipseプロジェクト作成時に予期しない問題の発生を防ぐため .classpath,.project ファイル, .settingsディレクトリ を削除しておきます。
(この時、myqr-project ディレクトリのフルパスが D:\myqr-project であるものとします)
次に、Eclipse の 新規プロジェクトウィザードで「動的Webプロジェクト」 または 「Dynamic Web Project」を選択し、 以下の設定で新規プロジェクトを作成します。
Project name:myqr-project Project contents Directory:D:\myqr-project
※上記の他の設定はデフォルト値で構いません。
以下の設定を行います。
ant.jar ant-launcher.jar quickreflector-silvergear.jar quickreflector-webcore.jar servlet-api.jar
myqr-project/WebContent/WEB-INF/web.xml を開き、pagesource-root の値を実際のパスにします。
修正前) <init-param> <param-name>pagesource-root</param-name> <param-value>c:/temp/quickreflector/quickreflector-examples</param-value> </init-param> 修正後) <init-param> <param-name>pagesource-root</param-name> <param-value>D:/myqr-project</param-value> </init-param>
以上で設定は完了です。
[サーバー]ビューで追加したサーバーを選択し、[始動]でTomcatを起動します。
起動後、以下のURLにアクセスすると、サンプルの動作を確認可能です。
http://localhost:8080/myqr-project/examples/sample1.jsx
http://localhost:8080/myqr-project/examples/sample2.jsx
http://localhost:8080/myqr-project/examples/sample3.jsx
http://localhost:8080/myqr-project/examples/sample4.jsx
http://localhost:8080/myqr-project/examples/sample5.jsx
http://localhost:8080/myqr-project/examples/sample6.jsx
http://localhost:8080/myqr-project/examples/sample7.jsx
http://localhost:8080/myqr-project/examples/sample8.jsx
sample1.jsx の場合は、sample1.html が表示されています。その他のファイルも同様です。
※ web.xml を以下のように設定すると、sample1.html へのアクセスでも同様の結果を得られます。
<servlet-mapping> <servlet-name>JsxServlet</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
以上でサンプルプロジェクトが動作する開発環境が整いました。
このプロジェクトをベースに開発をスタートさせていください。
※うまく動作しない場合は こちら も確認してください。
ページを作る
タグ要素を表示制御する(コメント)
変数を参照する
変数に値を設定する
HTTPヘッダを書く
他のページを組み込む
ループを書く
ページの元となるソースファイル(htmlファイル)は web.xml に記述した pagesource-root が指すディレクトリの下の、pagesource が指すディレクトリの下に保存してください。このディレクトリ以下のパスがそのまま URL のコンテキストパスに対応するようになっています。
ソースファイルの拡張子は .html です。中身は XHTML として記述してください。ただし、DOCTYPE は XHTML でなくともかまいません。DOCTYPE はそのまま出力に使われます。(現状DOCTYPEの指定はできません。近いうちに指定ができるように対処します)
※xhtmlの記述が正しければ特にエラーは出力されません
タグ要素は通常、そのまま出力されます。出力されないようにしたいときは、以下に挙げる3つの方法から選択できます。
ext:show を指定する方法は QuickReflector の拡張機能です。ext:show="true" とすると出力されるようになります。
この機能を使うと、HTMLファイルを直接ブラウジングしたときには表示、アプリケーションで出力したときには非表示になりますので、
HTMLファイルに直接デザイナー向けのコメントや、ダミーデータを記述することが可能になります。
例)コメントの出しわけ
comment1.html
<html><body> <!-- HTML Comment (開発者向けコメント) --> <span ext:show="!true">QuickReflectorのコメント(デザイナー向けコメント)</span> </body></html>
comment1.html を直接ブラウザで表示した場合
QuickReflectorのコメント(デザイナー向けコメント)
comment1.html をQuickReflectorを通してブラウザ表示した場合
(何も表示されません)
※HTMLコメントの出力レベルを設定できる機能がありますが、現在はインターフェースが変更される可能性が高いため、仕様が固まってから公開します。
htmlで変数を参照するには、事前にロジック側で VariableContainer#put で画面に表示するオブジェクトを格納しておきます。
その上でhtmlをレンダリングすると、 ${ と } で括った領域は出力の際に対応する変数の値で置換されます。
たとえば、${data} とするとページに対して与えられた変数マップから "data" をキーとする値を参照し、その値を展開します。
また、変数にHTMLタグを含む文字列が格納されており、それをHTMLエスケープせず
そのまま出力したい場合は、
${data.NOESCAPE}
と記述します。
例) 各オブジェクトを表示
var1.html
<html><body>
<span ext:language="java" ext:target="Var1.java"/>
msg=${msg}<br/>
<br/>
array[0]=${array.0}<br/>
<br/>
list[1]=${list.1}<br/>
<br/>
map.name=${map.name}<br/>
</body>
</html>
Var1.java
package examples;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
public class Var1 implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// 各変数を格納
container.put("msg", "Hello!");
String[] strings = {"My", "Name"};
container.put("array", strings);
List list = new ArrayList();
list.add("List1");
list.add("List2");
container.put("list", list);
Map map = new HashMap();
map.put("name", "ミスター");
container.put("map", map);
}
}
var1.htmlへのアクセス結果
msg=Hello! array[0]=My list[1]=List2 map.name=ミスター
ext:language="java" の場合、指定したJAVAファイルは JavaPageMarker を実装する必要があります。
さらに
public void invoke( Parameters params )
メソッドを宣言することで、html上の
<span ext:language="java" ext:target="Var1.java"/>
が解析されたタイミングで、Var1#invoke メソッドが実行されます。
${data}の data が示すオブジェクトが子要素を持つ場合、以下の参照例で示すように子要素を展開できます。
${} 記載方法
| dataの内容 | 参照例 | 展開される内容 |
|---|---|---|
| リスト(100, 200, 300) | data.0 | 100 |
| 配列('A', 'B', 'C') | data.2 | C |
| マップ ((no:'red', value:'apple'), (no:'blue', value:'berry')) |
data.blue | berry |
| システムプロパティ | data.'file.encoding' | MS932(Windowsデフォルト) |
| bean(getField()がある) | data.field | (data.getField()の戻り値) |
| null | data data.key |
(null)という文字列 |
変数参照の途中で ; (セミコロン)を入れると } の直前までをコメントとみなします。${key; キー参照}という記述で展開内容をコメントとして残しておくことができます。
${} の中に ${} を入れて再帰的に展開させることはできません。${key${num}} と記述すると、"key${num" という変数を探して結果を展開し、最後の } がテキストとして出力されます。
また、変数にはプリフィックスをつけることができます。これは変数が格納されている場所を示すもので、プリフィックスとコロンを変数の頭につけて位置を直接に指定できます。
プリフィックスとして提供されるのは以下の8種類で、それぞれが参照するオブジェクトが違います。
プリフィックス一覧
| プリフィックス | 参照先オブジェクトのクラス | getter | setter |
|---|---|---|---|
| CONFIG | javax.servlet.ServletConfig | getInitParameter | なし |
| ROOTDEF | java.util.Map | get | put |
| CONTEXT | javax.servlet.ServletContext | getParameter | なし |
| CONTEXT_A | javax.servlet.ServletContext | getAttribute | setAttribute |
| SESSION | javax.servlet.http.HttpSession | getAttribute | setAttribute |
| REQUEST | javax.servlet.http.HttpServletRequest | getParameter | なし |
| REQUEST_A | javax.servlet.http.HttpServletRequest | getAttribute | setAttribute |
| PAGE | java.util.Map | get | put |
プリフィックスをつけないで変数を取り扱うと表の下の方から参照し、最初に見つかった値を利用します。また、書き込みの場合はPAGEプリフィックスが示すマップへ書き込みを行います。
例) プリフィクスの利用例
var2.html
<!-- リクエストパラメータ name を出力 -->
name=${REQUEST:name}
<!-- どこかのスコープに存在する name を出力 -->
name=${name}
Var2.java
// リクエストパラメータ name を取得
String name = (String) container.get("REQUEST:name");
// セッションに独自クラスUserInfoを設定
container.put("SESSION:userInfo", userInfo);
<span ext:set="def"> # 値の設定ができます count = 18 number = 21 SESSION:data = data </span>
上記の記述でページソース内で変数に値を割り当てることができます。
1行にひとつずつ「変数名 = 値」という設定ができます。右辺の値は左右の空白を除去した文字列として割り当てられます。
span タグの中を<!-- -->で括っても処理されます。
<span ext:set="http-header"> # HTTPヘッダを設定できます Content-Type: text/html; charset=Windows-31J </span>
上記の記述でページ出力の際のHTTPヘッダの内容を設定することができます。
1行にひとつずつ「変数名 : 値」という設定ができます。両辺の値は左右の空白を除去した文字列として割り当てられます。
span タグの中を<!-- -->で括っても処理されます。
他のページを組み込む
<span ext:include="./other.html"/> この位置に記述した内容は破棄されます </span>
上記の記述で他のページを現在のページの出力に組み込むことができます。タグの中に記述した内容はすべて破棄されます。
これは JSP が持つ jsp:include の機能とは異なり、他のページの出力結果を取り込むものではないためパラメータ指定はできません。
なお、XMLの制約により組み込まれる側のページには少なくとも一つのタグがなければなりません。このタグが紛れ込むことを避けるため、ext:wrap="false" という属性をページのタグに入れておくことができます。
ループを書く
<span ext:loop="3,i">
label${i; ループ変数は0からカウントアップされます。}<br>
</span>
上記の記述でlabel0,label1,label2という文字列を3行にわたって展開することができます。ext:loopの値として指定できるのは、0以上の整数値あるいは java.util.Collection の派生クラス、または配列を示すキー値です。整数値のほかはページ作成だけでは供給できないため、プログラム作成の方で解説しています。
例) ループの例
Loop1.java
package examples;
import java.util.ArrayList;
import java.util.List;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
public class Loop1 implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// 変数を格納
List list = new ArrayList();
list.add(new Bean("Mr"));
list.add(new Bean("Mss"));
container.put("bean_list", list);
}
}
Bean.java
package examples;
public class Bean {
private String name;
public Bean(String name) {
this.name = name;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
loop1.html
<html><body>
<span ext:language="java" ext:target="Loop1.java"/>
<span ext:loop="bean_list,b">
name=${b.name}<br/>
</span>
</body>
</html>
出力結果
name=Mr name=Mss
ロジックを作る
ロジッククラスの特徴
リクエストパラメータを取得する
セッションにアクセスする
フォワード、リダイレクトする
htmlファイル内のspan タグの属性に ext:target が定義されていると、その属性値をロジックファイルへの相対パス、として解釈し、
そのロジックファイルをコンパイル・ロード・実行します。
コンパイル、ロードはロジックファイルが前回コンパイル時から変更されていた場合のみ行います。
例) var3.html リクエスト時に Var3.java を実行
var3.html
<html><body> <span ext:language="java" ext:target="Var3.java"/> </body> </html>
ロジックファイル Var3.java
package examples;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
public class Var3 implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
}
}
ロジックファイル内でリクエストパラメータ取得、セッション処理、他クラス呼び出し、など実際の処理を行います。
※ロジックファイルは各種スクリプト言語に対応していますが、ここでは Javaのみを対象として説明します。
ロジッククラスには以下の特徴があります。
リクエストパラメータを取得するには、
contaner.get("REQUEST:パラメータ名")
と記述します。
慣れるまではcontanerに明示的にリクエストプリフィクスを指定した方が良いでしょう。
パラメータが存在しない場合は null を返します。
例) ロジックファイル Req.java
package examples;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
public class Req implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// リクエストパラメータ name を取得
String name = (String)container.get("REQUEST:name");
}
}
HTTPセッションを操作するには、
[取得] contaner.get("SESSION:属性名")
[設定] contaner.put("SESSION:属性名", オブジェクト)
と記述します。
例) ロジックファイル Ses.java
package examples;
import java.util.HashMap;
import java.util.Map;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
public class Ses implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// セッションからDummyMapを取得
Map map = (Map)container.get("SESSION:dummyMap");
if (map == null) {
map = new HashMap();
map.put("user_id", "0");
// セッションにDummyMapを格納
container.put("SESSION:dummyMap", map);
}
}
}
ページの出力を中止してフォワード、リダイレクト、エラーステータス返却、中止等を行いたい場合は、
params から getRenderer() でレンダラを取り出し、
setAbort( Object ) メソッドで実行します。
その際、以下のプリフィックスを指定して動作を指定します。
abort プリフィックス一覧
| 記述例 | 概要 |
|---|---|
| FORWARD:/examples/x.jsx | x.jsxにフォワード |
| SEND:http://www.sourceforge.net/ | www.sourceforge.netへリダイレクト |
| ERROR:code,message | codeに指定したステータスコードを返す |
| END: | ページの出力を中止する。プログラム内で別の出力を行った後にこれを行う |
例) ロジックファイル ForwardRedirect.java
package examples;
import quickreflector.silvergear.Renderer;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
public class ForwardRedirect implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// リクエストパラメータ name を取得
String name = (String)container.get("REQUEST:name");
Renderer renderer = params.getRenderer();
if (name == null) {
// name が存在しない場合は
// http://www.sourceforge.net/ へリダイレクト
renderer.setAbort("SEND:http://www.sourceforge.net/");
} else {
// その他はx.jsx へフォワード
renderer.setAbort("FORWARD:/examples/x.jsx");
}
}
}
setAbortでフォワードした場合は、それまでのhtmlのレンダリング内容は破棄され、
新たにフォワード先のhtml,ロジックが実行されます。
その際、全htmlに共通の初期処理を行うよう記述している場合は、フォワード後に再度初期処理が実行されても、
問題ないように動作することを考慮して開発する必要があります。
QuickReflectorはHTMLのタグに属性を追加することで、様々な動作を指定します。
その属性の機能と記述方法について説明します。
1. 全タグ共通注意事項
2. ext:show
3. ext:wrap
4.ext:language
5. ext:target
6. ext:set=def
7. ext:set=http-header
8. ext:loop
9. ext:include
| 動作 | spanタグで囲んだ領域を表示制御する |
|---|---|
| 設定値 | true:表示する, false:非表示とする(!trueでも可) |
| $変数記述 | 可能(boolean値) |
| タグ内評価 | 評価する |
| 必須属性 | 無し |
ext:show 属性は、属性を記述した span タグで囲んでいる領域を表示するかどうか指定します。
記述例
<span ext:show="!true">このテキストはブラウザで開くと表示されるが、QuickReflectorでは削除する</span>
<span ext:show="true">このテキストはブラウザで開くと表示され、QuickReflectorでも表示する</span>
<span ext:show="${isDisplay}">このテキストはブラウザで開くと表示され、QuickReflectorでは isDisplay 変数が true の場合のみ表示する</span>
| 動作 | 属性を記述したspanタグを表示制御する |
|---|---|
| 設定値 | true:表示する, false:非表示とする(!trueでも可) |
| $変数記述 | 可能(boolean値) |
| タグ内評価 | 評価する |
| 必須属性 | 無し |
ext:wrap 属性は、属性を記述した span タグを出力するかどうか指定します。
記述例
<span ext:wrap="false">spanタグは表示されません</span> <span ext:wrap="true">spanタグは表示されます</span>
| 動作 | spanタグ解析時に実行するソースの言語を指定する |
|---|---|
| 設定値 | 以下のいずれかを指定します。 java, rhino, beanshell, pnuts, jython, judoscript |
| $変数記述 | 不可 |
| タグ内評価 | 評価しない(※将来的に評価可能にする予定です) |
| 必須属性 | ext:target |
ext:language 属性は、spanタグを解析したタイミングで実行するソースファイルの言語を指定します。
ext:target とセットで利用しますので、詳細は ext:targetを確認してください。
| 動作 | spanタグ解析時に実行するソースファイルの相対パスを指定する |
|---|---|
| 設定値 | ソースファイル相対パス |
| $変数記述 | 不可 |
| タグ内評価 | 評価しない(※将来的に評価可能にする予定です) |
| 必須属性 | ext:language |
ext:target 属性は、spanタグを解析したタイミングで実行するソースファイルの相対パスを指定します。
ext:language 属性とセットで利用します。
記述例 1. contents1.html と同じフォルダの Contents1.java を実行する。
[contents1.html] <html> <body> <span ext:language="java" ext:target="Contents1.java"/> </body> </html>
記述例 2. contents2.html から、相対パスに存在する ../common/Common.java を実行する。
[contents2.html] <html> <body> <span ext:language="java" ext:target="../common/Common.java"/> </body> </html>
| 動作 | 変数を設定する |
|---|---|
| 設定値 | def |
| $変数記述 | 不可 |
| タグ内評価 | 変数記述式として評価 |
| 必須属性 | 無し |
ext:set="def" 属性は、spanタグで囲んだ範囲に変数を設定するための属性です。
1行にひとつずつ「変数名 = 値」という設定ができます。
右辺の値は左右の空白を除去した文字列として割り当てられます。
span タグの中を<!-- -->で括っても処理されます。
設定した変数は、${変数名} と記述して出力します。
記述例
<span ext:set="def"> # 値の設定ができます count = 18 number = 21 SESSION:data = data </span>
| 動作 | HTTPヘッダを設定する |
|---|---|
| 設定値 | http-header |
| $変数記述 | 不可 |
| タグ内評価 | HTTPヘッダ変数記述式として評価 |
| 必須属性 | 無し |
ext:set="http-header" 属性は、spanタグで囲んだ範囲にHTTPヘッダ設定を記述するための属性です。
1行にひとつずつ「変数名 : 値」という設定ができます。
両辺の値は左右の空白を除去した文字列として割り当てられます。
span タグの中を<!-- -->で括っても処理されます。
記述例
<span ext:set="http-header"> # HTTPヘッダを設定できます Content-Type: text/html; charset=Windows-31J </span>
| 動作 | spanタグで囲んだ領域を繰り返し表示する |
|---|---|
| 設定値1 | 0以上の整数値 または 変数名(キー値) |
| 設定値2 | 現在の要素を示す変数名 |
| $変数記述 | 可能(Collection,配列) |
| タグ内評価 | 評価する |
| 必須属性 | 無し |
ext:loop 属性は、属性を記述した span タグで囲んでいる領域をループ表示する属性です。
設定値1 と 設定値2 はカンマ区切りで記述します。
設定値1 に整数値を指定した場合は、その整数値分のループ処理を行い、設定値2 で設定した変数に現在のインデックス値が格納されます。
設定値1 にCollectionの派生クラス、または配列オブジェクトの変数名を指定した場合は、そのリスト・配列の件数回ループし、設定値2 で設定した変数にリスト・配列の現在のループ要素が格納されます。
記述例 1. 整数ループ
<span ext:loop="3,i">
label${i},
</span>出力結果
label0,label1,label2
記述例 2. Listループ
Loop1.java
package examples;
import java.util.ArrayList;
import java.util.List;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
public class Loop1 implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// 変数を格納
List list = new ArrayList();
list.add(new Bean("Mr"));
list.add(new Bean("Mss"));
container.put("bean_list", list);
}
}
Bean.java
package examples;
public class Bean {
private String name;
public Bean(String name) {
this.name = name;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
loop1.html
<html><body>
<span ext:language="java" ext:target="Loop1.java"/>
<span ext:loop="bean_list,b">
name=${b.name}<br/>
</span>
</body>
</html>
出力結果
name=Mr name=Mss
| 動作 | 他のページをインクルードする |
|---|---|
| 設定値 | インクルードファイル相対パス |
| $変数記述 | 不可 |
| タグ内評価 | 評価しない(無視される) |
| 必須属性 | 無し |
ext:include 属性は、他のページを現在のページの出力に組み込むことができます。タグの中に記述した内容はすべて破棄されます。
JSP が持つ jsp:include の機能とは異なり、他のページの出力結果を取り込むものではないためパラメータ指定はできません。
なお、XMLの制約により、組み込まれる側のページには少なくとも一つのタグが存在していなければなりません。
※最終的なブラウザへの出力にこのspanタグが出力されることを避けるため、ext:wrap="false" という属性をページのタグに入れておくことをオススメします。
記述例
<span ext:include="./other.html"/> この位置に記述した内容は破棄されます </span>
共通ヘッダ・共通処理を入れる
特定のページのみに共通のチェック処理を入れる
一般的なWEBアプリでは、html 内の head タグや、bodyタグ内の 共通ヘッダ、フッタ は共通化されます。
QuickReflectorでは、インクルードを利用して、ヘッダ、フッタの共通化を行うことができますが、
それに加えて、インクルードされるhtmlにロジックを指定することで、共通的なロジックを定義することが可能になります。
例) 共通初期処理ロジック CommonInit.java で格納した値を 個別の画面 contents1.htmlで表示する
contents1.html
<html>
<span ext:include="../common/header.html"/>
<body>
<span ext:language="java" ext:target="Contents1.java"/>
init_name=${init_name}
</body>
</html>
Contents1.java (基本的に何もしていません)
package def;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
public class Contents1 implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// 初期処理で格納した値を取得
String init_name = (String) container.get("init_name");
}
}
header.html
<div ext:wrap="false"> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"/> <title>Sample</title> <link rel="stylesheet" type="text/css" href="../css/master.css" /> <script type="text/javascript" src="../js/jquery-1.2.1.js"></script> </head> <span ext:language="java" ext:target="../common/CommonInit.java"/> </div>
CommonInit.java
package common;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
import quickreflector.webcore.variablecontainer.VariableContainer;
public class CommonInit implements JavaPageMarker {
public void invoke( Parameters params ) throws Exception {
// 変数コンテナを取り出す。
VariableContainer container = params.getVariables();
// 共通初期値を格納
container.put("init_name", "CommonInitで設定しました");
}
}
実行結果
init_name=CommonInitで設定しました
ポイントは、 header.html 内で header タグの出力を定義しつつ、CommonInit.java クラスを実行している点です。
QuickReflectorは、htmlの途中に include が存在した場合、include されるファイルを解析します。
その中に ext:language="java" ext:target= の指定があれば、そのロジックを実行します。
このように、インクルードファイルの中に初期処理を含めることで、ページ全体の初期処理を行うことが可能になります。
例えば、ログインが必要なページを開発する場合は、セッションの状態で判断し、リダイレクト等の処理を行うケースがあります。
そのような場合、QuickReflectorではログインチェックを行うページをインクルードし、そのページでログインチェックを行うことで、
非常に管理し易いログインチェック処理を開発できます。
例) contents2.htmlの表示時にログイン中かどうかチェックし、ログインしていない場合はトップへリダイレクトする
contents2.html
<html>
<span ext:include="../common/header.html"/>
<span ext:include="../common/logincheck.html"/>
<body>
<span ext:language="java" ext:target="Contents1.java"/>
init_name=${init_name}
</body>
</html>
logincheck.html
<div ext:wrap="false"> <span ext:language="java" ext:target="../common/LoginCheck.java"/> </div>
LoginCheck.java
package common;
import quickreflector.webcore.helper.Parameters;
import quickreflector.webcore.helper.scriptdriver.JavaPageMarker;
public class LoginCheck implements JavaPageMarker {
/* (non-Javadoc)
* @see quickreflector.webcore.helper.scriptdriver.JavaPageMarker#invoke(quickreflector.webcore.helper.Parameters)
*/
public void invoke( Parameters params ) throws Exception {
// ログインチェック(セッションも利用可能)
// ログイン中で無ければ http://example.jp/ へリダイレクト
params.getRenderer().setAbort("SEND:http://example.jp/");
}
}
上記のように、ログインが必要なページのみ
<span ext:include="../common/logincheck.html"/>
を宣言することで、ログインチェック&フォワード・リダイレクトを自動的に行うようになります。
ログインチェックロジックが分離されているので、非常に管理しやすくなります。
技術情報 SilverGear
このページは準備中です。
技術情報 WebCore
このページは準備中です。
SourceForge.net Bugsに投稿してください。
英語でも日本語でも構いません。
Open Discussionに投稿してください。
英語でも日本語でも構いません。
PB-Lab 問い合わせよりお問い合わせ下さい。
英語でも日本語でも構いません。
ロードマップ
このページは準備中です。