チュートリアル
AzaraCでCGIを作るにはテンプレートとロジックという二つの要素が必要になります。
全体の流れとしては、ロジック側でプログラムの中心となる処理を行い、
その結果をテンプレートに埋め込んでいくことでHTMLを生成することになります。
ロジック側としては見た目のことなど気にしたくない、
テンプレート側としてはプログラムの細かい動作など気にしたくない、
という自然な要望からこのように分割されています。
Hello, World!
早速ブラウザに"Hello, World!"と表示するだけのCGIをAzaraCを用いて作ってみましょう。
テンプレートは次のようになるでしょう。
// hello.tpl(テンプレート側)
<%@ page Content-Type="text/html;" %>
<html>
<body>
Hello, World!
</body>
</html>
<%@と%>で囲まれた部分に、このテンプレートから生成されるテキストに関するメタ情報を書きます。
ここではブラウザにHTMLとして解釈してほしいということを指定しています。
残りの部分はHTMLの記述そのままです。ここに自由にHTMLを書いてください。
次にこのテンプレートを用いてHTMLを生成するロジック側の記述に入ります。
// hello.cpp(ロジック側)
#include <azarac/azarac.h>
using namespace azarac;
int main()
{
display("./hello.tpl");
}
hello.tplとhello.cppは同じディレクトリにあるものとします。
コード自体はAzaraCの提供するdisplay関数で先ほどのhello.tplを開くだけという簡単なものです。
ここでdisplay("./hello.tpl");ではなくてdisplay("hello.tpl");としてしまうと、
hello.tplが見つからない場合があるので注意しましょう。
では、このhello.tplとhello.cppをコンパイルしてみることにします。
これには以下のようにします。
g++ -lazarac -rdynamic -o hello hello.cpp
-rdynamicオプションというのを初めて見た人も多いかもしれませんが、
今は特に気にする必要はありません。
興味がある方はgccのマニュアル、もしくはin depthの頁を参照してください。
これでAzaraCを用いた完全なプログラムhelloが出来上がりました。
早速実行してみましょう。
$ ./hello
Content-Type: text/html;
<html>
<body>
Hello, World!
</body>
</html>
ブラウザから見ると、このようになります。
helloを始めて起動するときに少々時間がかかったと思いますが、
これはテンプレートをC++のコードに変換しコンパイルしているからです。
一度コンパイルされてしまえば、二度目からは高速に実行されることと思います。
<% %>タグ
テンプレートにはCの構文をそのまま含めることが出来ます。
折角なのでHello, World!を3回表示してみたくなったとしましょう。
その時は次のようにします。
// hello.tpl
<%@ page Content-Type="text/html;" %>
<html>
<body>
<% for (int i=0;i<3;++i) { %>
Hello, World!
<% } %>
</body>
</html>
非常に直感的。<% %>タグの中にCのプログラムをそのまま挟み込むことが出来ます
後は何も考えずにhelloプログラムを実行するだけです。
$ ./hello
Content-Type: text/html;
<HTML>
<BODY>
Hello, World!
Hello, World!
Hello, World!
</BODY>
</HTML>
ここで再コンパイルする必要が無かったというところが重要です。
helloを実行すると、自動的にテンプレートが更新さているかどうかを調べ、
もし更新されていたらテンプレートを再コンパイルしてくれます。
テンプレートのコンパイルについて
AzaraCの用意しているdisplay関数はテンプレートをテキストとして毎回解釈しているわけではありません。
一度テンプレートをC++のコードに変換し、
それをコンパイルすることで完全に機械語に置き換えてしまいます。
なのでテンプレート内にC++のコードを埋め込むことも出来るし、
二回目以降からテンプレートの実行は高速に行われるというわけです。
またdisplay関数は、呼び出されるたびにテンプレートが変更されているかどうかを調べます。
もし変更されていた場合はその場でテンプレートを再コンパイルしてから実行します。
この仕組みがあるおかげで、テンプレートはロジックとは切り離して編集することが出来るようになっています。
この辺りはJSPと同じ発想ですね。
ロジックとのデータのやりとり
CGIをテンプレートとロジックに分けれるとは言うものの、テンプレートからロジックのデータを使えなければ意味がありません。
これもAzaraCを使えば簡単に実現できます。
まずロジック側を見てみましょう。
// add.cpp
#include <azarac/azarac.h>
using namespace azarac;
string hello="Hello, World!";
int add(int a, int b)
{
return a;
}
int main()
{
display("./add.tpl");
}
mainの中は今までと同じ。ここでの目的はhelloという変数とaddという関数をテンプレート側から使うことです。
これらを使ったテンプレートは次のようになります。
// add.tpl
<%@ page Content-Type="text/html;" %>
<%!
extern string hello;
int add(int a, int b);
%>
<html>
<body>
<%= hello; %>
<%= add(3,7); %>
</body>
</html>
色々と新しい要素が出てきていますが、実行結果はすぐに予想がつくでしょう。次のようになります。
$ g++ -lazarac -rdynamic -o add add.cpp
$ ./add
Content-Type: text/html;
<html>
<body>
Hello, World!
3
</body>
</html>
さて、ではテンプレートを細かく見ていくことにしましょう。
まず<%! %>というタグが新しく出てきています。
これはC++でいうグローバル領域で、extern変数の宣言、関数宣言、#includeなどといったことを行う為の場所です。
今の場合、ここにhelloという変数とaddという関数を宣言しておくことで、
ロジック側で定義されている変数と関数を使うことが出来るようになります。
<%= %>タグは、中の式を評価して、そのままテキストとして出力するタグです。
<% %>タグとの違いは、中身を出力するかしないかということのみです。
<%= %>タグではstring,int,doubleといった型の値を出力することができます。
今回はこのタグを用いてhelloという変数の中身と、addという関数の結果を出力しています。
実際にブラウザから見るとこのようになります。
デバッグ
CGIを書くのにエラーはつき物です。
例えばAzaraCでも、テンプレートに書いたC++のコードが間違っているだとか、
テンプレートをコンパイルする権限が無い、などといった状況が考えられます。
このようにAzaraC内でエラーが起きたときに、
なぜエラーが起きたのかを返してくれるのがwhat()関数とwhat_html()関数です。
典型的には以下のようにして用います。
int main()
{
if (display("hello.tpl")<0) cout<<what();
}
こうしておくことにより、
display関数がなんらかの理由によりテンプレートを実行できなかったときに、
その理由を見ることが出来ます。
またテンプレートエンジンというライブラリの性質上、ブラウザからエラーを見たいことがあると思います。
その際に便利なのがwhat_html()関数で、エラーをHTMLに整形してから出力してくれます。
これもwhat()関数と同じように次のように使います。
int main()
{
if (display("hello.tpl")<0) cout<<what_html();
}
例えばテンプレートのコンパイルエラーに対する出力はこのようになります。
AzaraCがテンプレートから生成したC++を表示するため、少し直感的ではありませんが、
何も情報が無くただInternal Server Errorと言われるよりは幾分ましでしょう。
暗黙変数
AzaraCのテンプレート中では、いくつかの変数がデフォルトで使えるようになっています。
これらはJSPでいう暗黙変数と同じ役割を担っています。
各変数の細かい定義はリファレンスを参照してもらうことにして、
ここではユーザからformタグで送られてきた入力を受け取る方法を紹介します。
// param.tpl
<%@ page Content-Type="text/html;" %>
<html>
<body>
<form method="get" action="./param">
<input type="text" name="query">
<input type="submit" value="submit">
</form>
<%= escapeHTML(request.getParameter("query")); %>
</body>
</html>
ロジック側の説明は省略します。これを実行するとこのようなCGIが生成されます。
requestというのがユーザ側からサーバに送られてきた情報一般を扱う変数で、
この変数を通じて引数を受け取ることが出来ます。
Cookieの取り扱い
AzaraCではCookieも簡単に扱うことが出来ます。
アクセスするたびに数字が増えるカウンターCGIを作ってみましょう。
<%@ page Content-Type="text/html;"%>
<html>
<body>
<%
vector<Cookie> cookies=request.getCookies();
int counter=0;
for (int i=0;i<cookies.size();++i) {
if (cookies[i].getKey()=="counter") {
counter=fromString<int>(cookies[i].getValue())+1;
}
}
%>
<%= counter; %>
<%
Cookie new_cookie("counter", toString(counter));
response.addCookie(new_cookie);
%>
</body>
</html>
ここでもロジック側の説明は省略します。
Cookieは(キー,値)のペアから成り立っており、それぞれ任意の文字列を格納することが出来ます。
ここでは"counter"というキーを持ったCookieにカウンターの値をいれることにしましょう。
最初の<% %>タグ内のrequest.getCookies()でクライアント側から送られてきたCookieを全て取得しています。
この中から"counter"というキーを持ったCookieを選びだし、その値+1を変数counterに代入しています。
fromStringというのはAzaraC内で定義されているキャスト関数でstring型からint,doubleなど任意の型にキャストすることができます。
次の<%= %>タグでcounterの値をHTMLとして出力しています。
最後の<% %>タグは、更新されたcounterをもとに再びクライアント側にCookieを記録するように要請している部分です。
Cookie new_cookie("counter", toString(counter));でキーが"cookie"、値がcounterであるCookieを生成し、
次のresponse.addCookie(new_cookie);でこのCookieをクライアント側に送るよう設定しています。
このCGIを実際にコンパイルするとこのようになります。
|