QuickReflector

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 やユーザ条件によって同じソースから異なる出力が行われるような状況への対応が容易。

概要

QuickRefletorとは

概要
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/) へお願いします。
トップよりも下のページは更新により構成が変わる可能性があります。


開発元

PowerBEANS

機能一覧

機能一覧



QuickReflectorが提供する機能


  • HTML(XHTML)レンダリング機能
  • HTML(XHTML)への値バインド機能
  • HTML(XHTML)不正タグチェック機能
  • HTMLの不要改行・空行削除出力機能
  • HTMLコメント削除出力機能
  • JAVAソースファイル自動コンパイル・ロード機能
  • JAVAソースファイルコンパイル時の中間ファイル生成機能
  • 各種スクリプト言語ファイル実行機能(インタープリター)
  • ファイルインクルード機能
  • フォワード、リダイレクト機能
  • HTTPヘッダ出力機能
  • オブジェクトトランザクション機能

コンセプト

コンセプト



基本コンセプト

QuickReflectorは



QuickにWebアプリを開発し、

Quickな保守・メンテナンスを提供することで、

QuickなJAVAベースWebアプリ開発が可能、というイメージを持てる、



ことを基本コンセプトとしています。

ライセンス

ライセンス


QuickReflector は、BSD ライセンスに従ってご利用ください。



ソースコードはこちらから入手可能です。

ダウンロード

SourceForge QuickReflector サイトより最新のモジュール、ソースコードをダウンロードしてください。

セットアップ

インストール


QuickReflectorを既存のTomcat用WEBアプリケーションに追加する手順を説明します。

1から設定する場合は、事前に空のWEBアプリケーションをTomcatに設定し、動作確認を行っておいてください。

※ ホスト名:localhost, コンテキストパス:sample, Tomcat起動ポート:8080 とします



1. ダウンロード

SourceForgeの[Download QuickReflector]を選択し、最新のQuickReflectorをダウンロードしてください。



2. jarファイルの配置

ロジックの言語にJAVAを利用する場合は以下のファイルをWEBアプリケーションのクラスパスにコピーしてください。

通常は WEB-INF/lib フォルダにコピーすれば認識されます。



     quickreflector-silvergear-1.x.jar

     quickreflector-webcore-1.x.jar



※JAVA以外の言語で開発する場合は

   quickreflector-[言語名]-1.x.jar

 も同様にクラスパスにコピーします。



3. 必須ライブラリの追加

以下の必須ライブラリをクラスパスにコピー、または追加してください。


     ant.jar

     ant-launch.jar

     servlets.jar(Tomcat5.0以降の場合はservlet-api.jar)




4. JAVA_HOMEの確認

環境変数 JAVA_HOME が JDK をインストールしているディレクトリを指しているか確認してください。

もし指していない場合は、以下のいずれかの方法で対応してください。



対応方法1) JAVA_HOME に JDK インストールディレクトリを指定する

対応方法2) ${JDK}/lib/tools.jar ファイルを JAVA_HOME が指しているJRE配下の lib/ext ディレクトリにコピーする



5. web.xml に JsxServletを登録

以下の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ファイルを明示的に追加してください。



6. 動作確認

以上の設定で設定が完了しましたので、Tomcatを起動し動作を確認します。

Tomcatを起動し、該当コンテキストが正常起動されるかログを確認します。

正常起動されましたら、Tomcatを起動したまま以下の構成でファイルを作成します。


  • {ドキュメントルート}/WEB-INF/pages/def/index.html ファイル

  • {ドキュメントルート}/WEB-INF/pages/def/Index.java ファイル

    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、ドキュメントルート以外のパスに配置されることをオススメします。




上記ファイルを配置後、ブラウザで

 http://localhost:8080/sample/def/index.html

にアクセスし

 Hello QuickReflector!

が表示されればOKです。



7. フォルダ構成例

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プロジェクトを構築する手順を説明します。


1. ダウンロード

SouceForgeダウンロード一覧ページより、最新の quickreflector-examples.zip をダウンロードして解凍します。


2. Eclipse WEB プロジェクト作成

解凍した 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

※上記の他の設定はデフォルト値で構いません。


3. WEB プロジェクトの設定

以下の設定を行います。


  • プロジェクトプロパティの [Java のビルドパス]

    ソースパスに "myqr-project/pages" を追加します。

  • ライブラリファイルコピー

    myqr-project/WebContent/WEB-INF/lib ディレクトリに以下のファイルをコピーし、プロジェクトを更新します。
     ant.jar
     ant-launcher.jar
     quickreflector-silvergear.jar
     quickreflector-webcore.jar
     servlet-api.jar
    

  • web.xml の修正

    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にクラスパスを追加

    プロジェクトを[サーバーで実行]で一度実行・停止しサーバーを追加します。

    そして、[サーバー]ビューで追加したサーバーを選択し、[開く]で「サーバーの概要」ビューを表示します。

    ここで、[起動構成を開く]-[クラスパス] を選択し、[ユーザーエントリー] に 先ほど WEB-INF/lib に追加したjarファイルを追加します。

以上で設定は完了です。


4. WEB プロジェクトの起動

[サーバー]ビューで追加したサーバーを選択し、[始動]で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="!true" という属性を追加する。

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 タグの中を<!-- -->で括っても処理されます。



HTTPヘッダを書く

<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のみを対象として説明します。



ロジッククラスの特徴

ロジッククラスには以下の特徴があります。

  • 常にSingletonインスタンスで管理されます。そのためクラス変数は定数のみ宣言してください。
  • 独自のクラスを継承することが可能です。ただし、JavaPageMarker インターフェースは親クラスか子クラスで実装されている必要があります。



リクエストパラメータを取得する

リクエストパラメータを取得するには、

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


1. 全タグ共通注意事項


  • QuickReflectorの属性を記述できるHTMLタグは span のみです。その他のタグに記述しても無視されます。


2. ext:show

動作 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>


3. ext:wrap

動作 属性を記述したspanタグを表示制御する
設定値 true:表示する, false:非表示とする(!trueでも可)
$変数記述 可能(boolean値)
タグ内評価 評価する
必須属性 無し

ext:wrap 属性は、属性を記述した span タグを出力するかどうか指定します。



記述例

<span ext:wrap="false">spanタグは表示されません</span>
<span ext:wrap="true">spanタグは表示されます</span>


4.ext:language

動作 spanタグ解析時に実行するソースの言語を指定する
設定値 以下のいずれかを指定します。

java,
rhino,
beanshell,
pnuts,
jython,
judoscript
$変数記述 不可
タグ内評価 評価しない(※将来的に評価可能にする予定です)
必須属性 ext:target

ext:language 属性は、spanタグを解析したタイミングで実行するソースファイルの言語を指定します。

ext:target とセットで利用しますので、詳細は ext:targetを確認してください。


5. 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>


6. ext:set="def"

動作 変数を設定する
設定値 def
$変数記述 不可
タグ内評価 変数記述式として評価
必須属性 無し

ext:set="def" 属性は、spanタグで囲んだ範囲に変数を設定するための属性です。

1行にひとつずつ「変数名 = 値」という設定ができます。

右辺の値は左右の空白を除去した文字列として割り当てられます。

span タグの中を<!-- -->で括っても処理されます。

設定した変数は、${変数名} と記述して出力します。



記述例

<span ext:set="def">
  # 値の設定ができます
  count = 18
  number = 21
  SESSION:data = data
</span>


7. ext:set="http-header"

動作 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>


8. ext:loop

動作 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


9. ext:include

動作 他のページをインクルードする
設定値 インクルードファイル相対パス
$変数記述 不可
タグ内評価 評価しない(無視される)
必須属性 無し

ext:include 属性は、他のページを現在のページの出力に組み込むことができます。タグの中に記述した内容はすべて破棄されます。



JSP が持つ jsp:include の機能とは異なり、他のページの出力結果を取り込むものではないためパラメータ指定はできません。



なお、XMLの制約により、組み込まれる側のページには少なくとも一つのタグが存在していなければなりません。



※最終的なブラウザへの出力にこのspanタグが出力されることを避けるため、ext:wrap="false" という属性をページのタグに入れておくことをオススメします。



記述例

<span ext:include="./other.html"/>
  この位置に記述した内容は破棄されます

</span>

Tips

Tips


共通ヘッダ・共通処理を入れる

特定のページのみに共通のチェック処理を入れる


共通ヘッダ・共通処理を入れる

一般的な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

技術情報 SilverGear

このページは準備中です。

技術情報 WebCore

技術情報 WebCore

このページは準備中です。

サポート

不具合・要望・問い合わせ等の連絡先

不具合・要望・問い合わせ等の連絡先



不具合の報告先

SourceForge.net Bugsに投稿してください。

英語でも日本語でも構いません。



機能追加要望・技術的な質問

Open Discussionに投稿してください。

英語でも日本語でも構いません。



その他の問い合わせ

PB-Lab 問い合わせよりお問い合わせ下さい。

英語でも日本語でも構いません。

ロードマップ

ロードマップ

このページは準備中です。