トップ スクリーンショット マニュアル ダウンロード Wiki チャット
1 概要 2 使い方 3 ダウンロード 4 ライセンス 5 連絡先 6 最後に Appendix
ScalaでWebアプリケーションを簡単に作れないか調べていましたが、なかなかいいものがありません。一方JSPのScriptletを使えば様々な問題こそあれ、かなりハードルを下げることができます。
そこでJSPのコンセプトを取り入れ、
という機能を備えたWebフレームワークを作ってみました。
以前のWeb Flavor version 0.1は、Rhino(JavaScript)やJRuby(Ruby)などでも動きましたが、今回はScalaだけに特化し、Scalaの特徴を生かせるよう作られています。
「Better CGI, Better PHP!」
強く型にはめず、CGIやPHPのように手軽に、そして弱い枠組みで(かつ十分)Webアプリケーションを作れる環境を目指しています。
Web Flavorは以下の特徴をもっています。
以下の環境を用意してください。
Java | Java 5 Runtime Environment以上 |
---|---|
Java Servlet | Java Servlet 2.3以上 |
Java Servletコンテナ | Apache Tomcat 6以上(Tomcat 5以降でも動作すると思われる, Jettyなど他のコンテナは未確認) |
Scala | 2.7.1.final (標準添付) |
全環境を試していないので、動作しない環境があるかもしれません.
${WEB_FLAVOR_HOME}/webflavor.warをServletコンテナに配置(デプロイ)してください。
なお、Servletコンテナによっては正常に動作しない可能性があるので、${WEB_FLAVOR_HOME}/lib/scala-library.jarをServletコンテナのCLASSPATHに加えてください。
Flavorとは、Scalaの文法で書かれるWebアプリケーションのスクリプトです。
Web Flavorでは、Flavorを記述することによってWebアプリケーションを開発します。
詳細は、「A3 Flavorとは」をご覧ください。
作成したFlavorソースは、WEB-INF/src/下に置かれ、その相対パスがそのままアクセスパスにマッピングされます。
例えば、webflavorというディレクトリに配置した場合、
Flavorソース | URL |
---|---|
WEB-INF/src/examples/Foo.scala | http://localhost:8080/webflavor/examples/Foo.scala |
になります。
詳細は、「A4 Flavorソースの配置」と「A5 アクセスパスとFlavorソースのマッピングルール」をご覧ください。
Scalaから使いやすいようにJava Servlet APIをラッピングして提供されており、Java Servletと同じ要領で使うことができます。
詳細は、「A2 APIリファレンス」をご覧ください。
具体的な例を示しながら説明します。
たとえば、"Hello, world"を表示するFlavorを作ります。
// HelloWorld.scala // タイトル名 val TITLE = "Hello, world!" // Web Flavorエンジンに返されるXML要素 // レスポンスとして出力されます <html><body><h1>{TITLE}</h1></body></html>
ファイル名をHelloWorld.scalaとしてWEB-INF/srcに保存してください。文字コードはUTF-8です。
このソースは単なるテンプレートのように見えますが、そうではなく、これはScalaのコードになっています。
返り値を明示的に書いていないので、解りにくいかもしれませんが、最後の行は、
return <html><body><h1>{TITLE}</h1></body></html>
と等価です(Scalaではよくreturn文が省かれます)。
XML要素を返していますが、Stringやnullなどを返しても構いません。
リクエストしたパラメータなどを表示するFlavorを作ります。
// Echo.scala // タイトル名 val TITLE = "Echo" // Web Flavorエンジンに返されるXML要素 // レスポンスとして出力されます <html> <head> <title>{TITLE}</title> </head> <body> <h1>{TITLE}</h1> <h2>Headers:</h2> {for ((name, value) <- request.headers) yield <p>{name}: {value}</p>} <h2>Parameters:</h2> {for ((name, value) <- request.params) yield <p>{name}: {value}</p>} </body> </html>
ファイル名をEcho.scalaとしてWEB-INF/srcに保存してください。
requestはHttpServletRequest相当のインスタンスで、ヘッダー情報であるrequest.headers: Map[String,String]と、パラメータ情報であるrequest.params: Map[String,String]も用意されています。
それぞれSeq[String,String]であるので、そのままfor文でループを回して中身を得ることができます。
0.2.7からPOHP(Plain Old HTML Page)によるページ生成ができるようになりました。
この機能は、HTMLテンプレートを導入することでViewを分離でき、またPure HTMLをテンプレートにすることで、Webデザイナとの協業がしやすくなります。
まず最初に "src/POHPHelloWorld.html"(UTF-8) としてHTMLテンプレートを作成します。
<html> <head> <title><span flavor:id="title">title</span></title> </head> <body> <h1><span flavor:id="title"/></h1> <span flavor:id="message">Hello</span> </body> </html>
<span flavor:id="リソース名"/>要素が埋め込むリソースになります。
次にFlavorを "src/POHPHelloWorld.scala"(UTF-8) として作成します。
Template("", "title" -> Text("Hello, world!"), "message" -> <p>Hello, POHP world!</p> )
Template("ページ名", (String,Seq[scala.xml.Node])*) は、テンプレートオブジェクトを作成するメソッドです。
"title" -> Text(...) は、挿入するリソースを示しています。リソースは、Seq[scala.xml.Node]で、XML要素(XMLリテラルなど)をそのまま使えます。テキストの場合はTextメソッドを使ってXML要素に変換してください。
またテンプレートファイルとFlavorソースファイルは同じディレクトリに同じファイル名(拡張子はそれぞれ".html"と".scala")で置くようにしてください。
これだけで、リソース部分を書き換えたHTMLページを出力できます。
<html> <head> <title>Hello, world!</title> </head> <body> <h1>Hello, world!</h1> <p>Hello, POHP world!</p> </body> </html>
なお、同じURLのFlavorで複数の異なるページを返してやることができます。
"src/POHPHelloWorld.scala"で、
Template("Foo", "title" -> Text("Hello, world!"), "message" -> <p>Hello, POHP world!</p> )
とした場合、対象となるテンプレートは"src/POHP_HelloWorld_Foo.html"となり、ページ名と名前の組み合わせにより、複数ページを返すことが可能になります。
なお、デフォルトのページ名は""(0文字)です。
POHPテンプレートの詳細については「A9 POHPテンプレート」をご覧ください。
Context#attributesやSessionなど永続化されるオブジェクトの型をFlavorのソース内で定義し、Flavorソースを更新した場合、ClassCastExceptionが発生する可能性があります。
これは永続化されたオブジェクトと新しく作成したクラスのクラス空間(ClassLoader)が異なる為で、Servletコンテナを再起動する、あるいは、DeployしなおすまでClassCastExceptionが発生しつづけます。
いくつか解決策はあるのですが、
などの対策を行ってください。
動的ライブラリとは、Flavorで使われるライブラリで、Flavorとともにコンパイルされ、同じClassLoader上で動かす事ができます。
動的ライブラリを使うことでFlavorで使われるコードを共有でき、まだ動的にコンパイルされて使われるため、試行錯誤をしながら開発を進めていくことができます。
詳しくは「A10 動的ライブラリ」をご覧ください。
0.2.5から、Flavorを事前にコンパイルしてWeb Applicationとしてパッケージ化できるようになりました。
特徴としては、
と軽量にでき、Flavorで開発したプログラムをパッケージ化して運用するのに適しています。
開発手順としては、
となります。
flavorcコマンドやflavorc Antタスクについては、「A8 Flavor Compiler」をご覧ください。
なお、Servletコンテナに配置する前に、web.xmlを以下のように書き直してください。
<filter> <filter-name>WebFlabor</filter-name> <filter-class> jp.ne.cappuccino.keisuken.servlet.flavor.WebFlavorFilter </filter-class> ... <init-param> <param-name>staticMode</param-name> <param-value>true</param-value> </init-param>
staticModeをtrueにすると、Flavorは静的に動作するようになり、動的にコンパイルされなくなります。
WEB-INF/srcディレクトリのサンプルソースもご覧下さい.
0.2.0a3から新しく Administrator menu を設けました。
これは、Web Flavorを管理・操作する為のメニューで、現在は、
が行えるようになっています。
この機能により、Web FlavorをWebブラウザからFlavorソースコードを編集して実行できるため、Web Flavorのハードルを下げ、開発サイクルをあげることが出来ます。
またAministrator menu自体もFlavorで書かれています。
詳細については、「A7 Administrator menu」をご覧ください。
WebFlavor-samples-x.x.x.zipをダウンロードして適当なディレクトリに展開し、環境変数としてJAVA_HOME または JRE_HOMEにJavaのランタイムのホームディレクトリ(ex. C:\Program Files\Java\jre1.6.0_07)を設定した後、WebFlavor-samplesのstartup.batまたはstart.shを実行すれば、サンプルアプリケーションが起動します。
http://localhost:8080/にアクセスすれば、Web Flavorのサンプルアプリケーションを実行できます。
また、Administrator menuは、BASIC認証してありますので、ユーザ名: webflavor , パスワード: webflavor でログインしてください。
以下のページからダウンロードできます.
https://sourceforge.net/project/showfiles.php?group_id=242794
アーカイブ | 詳細 |
---|---|
WebFlavor-#.#.#.zip | ソースとWARファイルパッケージ |
WebFlavor-samples-#.#.#.zip | サンプルアプリケーション(Apache Tomcat込) |
以下のページからダウンロードできます.
ライセンスファイルを参照してください.
なお,このソフトウェアを使って生じた損害などについては,作者である西本 圭佑は一切責任をとりませんのでご了承ください.
また,Scalaなどのランタイムについても,各ライセンスファイルをご覧下さい.
質問や要望などがありましたら keisuken atmark cappuccino.ne.jp あるいは Twitterの @keisuke_n まで内容を書いてお送りください.
Administrator menuでソースの生成から編集までできるようになり、ちょっとしたCGIぽいものをServletコンテナ上で試すことができ、Scalaの記述性も助けて、便利に使えるものになったと思います。
パフォーマンスも、コンパイルに時間がかかることに目をつぶれば、生のJava Servletと同じくらいのパフォーマンスが出ると思います。
JSPのScriptletでも短いものは同様に軽快に書けていけますが、JSPの記述ルールをある程度覚えなくてはいけなかったり、XMLのタグの中にコードが埋もれてしまって、読みにくく書きにくいものになっています。
Web FlavorではScalaのコードのみ許すことによって、読みやすさや書きやすさを追求できますし、XMLリテラルがあるために、Viewをかなり簡単に記述できます。XSS(クロスサイトスクリプティング)が生じにくくなる良い副作用もあります。
通常ViewとControllerを混ぜて記述するのは推奨されせんが、Web FlavorではViewとController、場合によってはModelまで1つのソースファイルに書いてしまいます。しかし「それでもいい」と思わせてしまう魅力を持っていると思います。
しかしまだ未完成です.APIなどの仕様が大幅に変更される可能性がありますし,バグもたくさんあります、ドキュメントもまだまだ十分とはいえませんが、これからも改良していきたいと思います。応援してください。
以下の環境を前提にしています。
Java | Java 5 Runtime Environment以上 |
---|---|
Java Servlet | Java Servlet 2.3以上 |
Java Servletコンテナ | Apache Tomcat 6以上(Tomcat 5以降でも動作すると思われる, Jettyなど他のコンテナは未確認) |
Scala | 2.7.1.final (標準添付) |
Flavor APIは、Flavorを書くために必要なリソースや設定などを操作する為のAPIです。
Flavor GUI APIは、FlavorでFORMなどを書くときに使用する一種のフレームワークになっています。
主に、GUIコンポーネント(入力項目の表示と入力値の保持)とValidator(入力値のチェック)に分かれます。
Flavorとは、Scalaの文法で書かれるWebアプリケーションのスクリプトです。
以下のルールで作成します。
Web FlavorでのFlavorのソースは、UTF-8で記述します(固定)。
Flavorのソースは以下のように、
を継承したクロージャ(クラス)になっていて、context, request, response, sessionなどの変数はクロージャの引数として渡されます。
またクロージャ(クラス)の記述はWeb Flavorエンジンが自動的に付加してくれるため、クロージャの中身だけ記述すればいいようになっています。
import jp.ne.cappuccino.keisuken.servlet.flavor.{Context,Request,Response,FlavorUtils} import jp.ne.cappuccino.keisuken.servlet.flavor.HTMLUtils._ import java.io._ class {名前} extends (Context,Request,Response,Session) => AnyRef { def apply( context: Context, request: Request, response: Response, session: Session): AnyRef = { val __flavor_util__ = new FlavorUtils(context, request, response, session) import __flavor_util__._ // ここにFlavorのソースが記述される } }
返り値はそのままServletのレスポンスオブジェクトとして扱われ、
返り値 | 出力 |
---|---|
null | 何もしない |
String | 文字列 |
scala.xml.Node(XMLリテラルなど) | XML/(X)HTML |
Template(POHPテンプレート) | XML/(X)HTML |
Book(null/String/scala.xml.Node/Temlateなど) | 何もしない/文字列/XML/(X)HTML |
として出力されます。
また出力は、
によって設定でき、例えば
response.contentType = "text/plain; charset=Windows-31J"
とすれば、テキスト形式で文字エンコードはWindows-31Jとして扱われます。
基本的な手順は、
で、レスポンスオブジェクトを返す為のコードを記述することになります。
ScalaのXML要素はテンプレート的な使い方を始めかなり便利に使うことができますが、(X)HTMLに準拠したHTMLページを出力することができません。
そこで、response.documentTypeにHTMLタイプを代入すれば、XML要素で作ったHTMLを出力すれば(X)HTMLに準じたHTMLを出力できます。
HTML定数は、
定数 | (X)HTML/XMLタイプ |
---|---|
HTML_4_01_STRICT | HTML 4.01 Strictタイプ |
HTML_4_01_TRANSITIONAL | HTML 4.01 Transitionalタイプ |
XHTML_1_0_STRICT | XHTML 1.0 Strictタイプ |
XHTML_1_0_TRANSITIONAL | XHTML 1.0 Transitionalタイプ |
XML_1_0 | XML 1.0 |
があります。
以下にサンプルを示します。
// 各種処理 ... // HTMLタイプの設定 (XHTML 1.01 Transitional) response.documentType = XHTML_1_01_TRANSITIONAL // 出力するXMLオブジェクト <html> <body> </body> </html>
Response#documentTypeに設定すると、
をします。html要素などは、XML要素に示された通り出力しますので、xmlns属性やxml:lang属性などは開発者が定義します。
Flavorソース中では、
のクラスがインスタンス化されimportされているためのメソッドをそのまま呼び出すことができます。
作成したFlavorソースは、WEB-INF/src/下に置きます。配置されたFlavorソースは必要に応じてコンパイルされ実行されます。
例:
http://localhost:8080/webflavor/ にWeb Flavorを配置した場合、以下のようにマッピングされ実行されます。
URLパス | Flavorソースパス |
---|---|
/webflavor/Foo.scala | WEB-INF/src/Foo.scala |
/webflavor/Foo | WEB-INF/src/Foo.scala |
/webflavor/ | WEB-INF/src/Index.scala |
/webflavor/Index | WEB-INF/src/Index.scala |
/webflavor/Index.scala | WEB-INF/src/Index.scala |
/webflavor/examples/Boo.scala | WEB-INF/src/examples/Boo.scala |
/webflavor/examples/Boo | WEB-INF/src/examples/Boo.scala |
アクセスパスが"/"で終わる場合は、".../Index.scala"の扱いになります。
Web Flavor filterとは、Web Flavorを動かす為のランタイムで、ServletのFilterになっています。
デフォルトの設定(web.xml)は以下のようになっており、
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" version="2.5"> ... <filter> <filter-name>WebFlabor</filter-name> <filter-class> jp.ne.cappuccino.keisuken.servlet.flavor.WebFlavorFilter </filter-class> <init-param> <param-name>filterChain</param-name> <param-value>false</param-value> </init-param> <!-- <init-param> <param-name>source</param-name> <param-value>WEB-INF/src</param-value> </init-param> <init-param> <param-name>libSource</param-name> <param-value>WEB-INF/lib_src</param-value> </init-param> <init-param> <param-name>temporary</param-name> <param-value>WEB-INF/temp</param-value> </init-param> <init-param> <param-name>startupCompileAll</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>updateCheckInterval</param-name> <param-value>60</param-value> </init-param> <init-param> <param-name>staticMode</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>bbsHome</param-name> <param-value>/WEB-INF/bbs_data</param-value> </init-param> <init-param> <param-name>wikiHome</param-name> <param-value>/WEB-INF/wiki_data</param-value> </init-param> --> </filter> <filter-mapping> <filter-name>WebFlabor</filter-name> <url-pattern>/</url-pattern> </filter-mapping> <filter-mapping> <filter-name>WebFlabor</filter-name> <url-pattern>/Index.scala</url-pattern> </filter-mapping> <filter-mapping> <filter-name>WebFlabor</filter-name> <url-pattern>*.scala</url-pattern> </filter-mapping> <filter-mapping> <filter-name>WebFlabor</filter-name> <url-pattern>/samples/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>WebFlabor</filter-name> <url-pattern>/admin/*</url-pattern> </filter-mapping>
"/"、"/Index.scala"、"*.scala"、"/samples/*"、"/admin/*"にそれぞれマッピングされています。
また、Web Flavor Filterは、以下のパラメータを持っています。
パラメータ名 | 内容 |
---|---|
filterChain | Filterをchainする場合に使います。デフォルトは"false"で"true"にするとchainされます |
source | Flavorソースを配置するディレクトリを示します。デフォルトは"WEB-INF/src"で、変更する場合はWARファイルを配置したディレクトリから相対パスで指定してください |
libSource | Flavorソースに依存する動的ライブラリを配置するディレクトリです。デフォルトでは"WEB-INF/lib_src"で、変更する場合はWARファイルを配置したディレクトリから相対パスで指定してください |
temporary | Flavorをコンパイルするためのテンポラリディレクトリを示します。デフォルトは"WEB-INF/temp"で、変更する場合はWARファイルを配置したディレクトリから相対パスで指定してください |
startupCompileAll | スタートアップ時にFlavorソースをすべてコンパイルするかどうかを示します。デフォルトはfalseで実行しません。trueにするとすべてコンパイルします。ただし起動に時間がかかる可能性があります |
updateCheckInterval | Flavorソースの更新チェック間隔(秒)を示します。デフォルトは60秒です |
staticMode | Flavorを静的モード(静的クラスからインスタンス化するかどうか)を示します。デフォルトはfalseです。trueにすると、デフォルトクラスローダからFlavorを生成して実行します。静的モードにすると、あらかじめコンパイルされているため起動時間が早くなります。ただし動的にコンパイルされなくなるため注意が必要です |
Administrator menuは、Web Flavorの管理メニューです。
主な機能は、
です。
なお、セキュリティの設定(web.xml)は、以下のようになっており、"web-flavor-admin"ロールでBASIC認証されています。必要に応じて変更してください。
<security-constraint> <web-resource-collection> <web-resource-name>Admin area</web-resource-name> <url-pattern>/admin/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>web-flavor-admin</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>Admin area</realm-name> </login-config>
$FLAVOR_HOME/bin に flavorc (UNIX/Linux用シェル) および flavorc.bat があるので、それらにPATHを通してください。
flavorcのArgumentsは以下の通りです。
Usage: flavorc CLASSPATH DESTDIR SRCDIR CLASSPATH: コンパイルに必要なCLASSPATH DESTDIR: コンパイルされたクラスが置かれるディレクトリ SRCDIR: Flavorが置かれているディレクトリ
flavorc Antタスクを使うためには、Antタスク内でカスタムタスクを定義する必要があります。
<taskdef name="flavorc" classname="jp.ne.cappuccino.keisuken.servlet.flavor.tools.FlavorCompilerTask" classpath="${scala-compiler-jar}:${scala-library-jar}:${webflavor-jar}" />
次にflavorc Antタスクを使ってコンパイルの定義を記述します。
<!-- ${classpath}: コンパイルに必要なCLASSPATH ${destdir}: コンパイルされたクラスが置かれるディレクトリ ${srcdir}: Flavorが置かれているディレクトリ --> <flavorc srcdir="${flavor-srcdir}" destdir="${classes}" classpath="${classpath}" />
POHPテンプレートは、UTF-8で書かれたHTMLファイルです。
このテンプレートファイルにFlavorによって与えられるXMLリソースを埋め込んで最終的なページ(HTML/XHTML)を出力します。
Flavorソース名と同じディレクトリに同じ名前をつけて配置します。ただし拡張子は".html"をつけてください。
Flavorソースパス | HTMLテンプレートパス |
---|---|
src/examples/Foo.scala | src/examples/Foo.html |
POHPテンプレートであるHTMLには、Flavorから挿入したい個所にリソースタグを記述します。
<!-- src/examples/Foo.html --> <html> <body> <span flavor:id="foo">ダミーメッセージ</span> </body> </html>
リソースタグは、次の2つの形式があります。
リソース名は、Flavorで挿入する名前と同じものにしてください。
Flavorは、以下のように記述します。
// src/examples/Foo.scala Template("ページ名", "foo" -> <h1>Hello, world!</h1> )
Foo.htmlのリソースタグの場所に、リソース名で与えたXML要素(Seq[scala.xml.Node]を挿入してくれます。
またページ名は、同じURLのFlavor(Foo.html)に複数のページを返す為に必要なもので、デフォルト時は""(0文字)を与えます。
POHPテンプレートの命名規則は、以下のようになります。
Flavorパス | ページ名 | HTMLテンプレートパス |
---|---|---|
examples/Foo.scala | "" | examples/Foo.html |
examples/Foo.scala | "boo" | examples/Foo_boo.html |
exmaples/Foo.scala | "bar" | examples/Foo_bar.html |
動的ライブラリとはFlavorに依存した動的に決定されるライブラリであり、Flavorとともに動的にコンパイルされ、Flavorと同じClassLoader上で実行されます。
動的ライブラリを使うことでWebアプリケーションのコードを共有でき、Flavorの開発とともに試行錯誤しながら開発を進めることができます。
動的ライブラリは、通常"WEB-INF/lib_src"に置かれ、Flavorから参照されます。
ルートパッケージでは参照されない為、必ずパッケージをつけます。
// WEB-INF/lib_src/examples/HelloWorld.scala package examples object HelloWorld { def message = "Hello, world!" }