ColdFusion-開発効率を求められる今だから知りたい高性能Webアプリケーションサーバー

第3回ColdFusionでデータベースにアクセスする

第2回目の記事ではColdFusionの開発環境を手持ちのPCにインストールする方法をご紹介しました。WindowsとMac OS XではGUIベースのインストーラーが提供されているため、通常のアプリケーションをインストールするのと同じような感覚でColdFusionをインストールすることができます。Linuxに関しては、CUIベース(テキストベース)のインストーラーとなってしまいますが、インタラクティブなインストーラーであるため、比較的簡単にColdFusionをインストールすることができます。手元のマシンでColdFusionを無償で体験する環境を整えることは比較的簡単だと言うことが分かりました。

今回の記事では、ColdFusion 8付属のサンプルデータベースに対してクエリーを発行する例をご紹介します。

ColdFusion付属のサンプルデータベースはApache Derby

ColdFusion 8からサポートされたデータベースとしてApache Derbyがあります。Apache DerbyとはJavaで書かれたデータベースで、Google GearsAdobe AIRで採用されているSQLiteのように、アプリケーション組み込み型データベースとして機能させることもできます。ColdFusionはJavaベースであるため、Javaで書かれているApache Derbyと相性がよいこと、及びApache Derbyはアプリケーションに組み込めるという特性を生かし、ColdFusionに組み込まれるようになりました。そのため、ColdFusion 8から付属のサンプルデータベースはApache Derbyデータベースが採用されるようになりました。

データソース- データベースへの接続の単位

さて、ColdFusionにはデータソースという概念があります。データソースとは『どのデータベースサーバーの、どの名前のデータベースに、どのユーザーアカウントで接続するか、その際のJDBC接続パラメーターは何か、許可するSQL文は何か』などという情報をまとめたものです。ColdFusionではcfqueryタグでクエリーを実行する際に、datasource属性にクエリーに使用するデータソースを指定するだけでクエリーを実行できます(クエリーを実行する部分にデータベースサーバーのIPアドレスやアカウント情報を記述する必要はありません⁠⁠。

データソース単位でデータベースへの接続方法を管理することで、CFMLテンプレート上にデータベースへの接続パスワードなどを書く必要が無いため、データベースパスワードの漏洩のリスクを軽減することができます。また、ColdFusion Administrator上でデータソースの設定内容を変更するだけで、そのデータソースを使っている全てのクエリーの接続先データベースサーバーなどを一度に変更することができます。データベースサーバーのIPアドレスが変更になった際などは、面倒無く移行することができるでしょう。

データソースを管理する

ColdFusion Administratorを開き(http://127.0.0.1:8500/CFIDE/administrator/ IPアドレスはColdFusionをインストールしたマシンのIPアドレスに読み替えてください⁠⁠、左側のメニューから「データソース」を選択してください。すると、そのColdFusionに設定されているデータソースの一覧が出てきます。サンプルデータベースがインストールされた状態であれば4つ出てくると思います。

図1 ColdFusion Administratorのデータソース管理画面
図1 ColdFusion Administratorのデータソース管理画面

設定内容を閲覧してみましょう。cfartgalleryの左側に並んでいる3つのアイコンの一番左の「編集」アイコンをクリックしてみてください。cfartgalleryの設定内容が表示されるはずです。

図2 データソース「cfartgallery」の設定内容
図2 データソース「cfartgallery」の設定内容

cfartgalleryの場合、Apache Derbyデータベースのため、データベースサーバーのIPアドレス入力欄などが無い代わり、Apache Derbyデータベースのデータディレクトリを設定する欄があります(例ではC:\ColdFusion8\db\artgalleryとなっています⁠⁠。そのほか、この画面から各種設定の閲覧・編集が可能です。

データソースを追加することもできます。追加するには、データソースの一覧が出ていた画面に戻り図1⁠、⁠新規データソースの追加」のフォームに、新しく追加するデータソースの名前と、データベースドライバの種類(OracleやMySQLなど)を選び、⁠追加」ボタンを押します。すると、そのデータベースドライバ固有のデータソース設定画面に移行します。必要事項を記入後、⁠送信」ボタンを押せば、そのデータソースが使用できるようになります。

図3 MySQL 4/5ドライバでの設定画面
図3 MySQL 4/5ドライバでの設定画面

サンプルデータベースにクエリーを発行する

それでは、ColdFusion付属のサンプルデータベースに対してクエリーを発行してみることにしましょう。cfartgalleryデータソースを用いて、artテーブルから「mediaID=2」の条件にマッチする行を取得してくる例です。cfartgalleryはアートギャラリーの商品在庫を管理しているデータベースで、artテーブルには商品の在庫情報が入っています。テーブル構成は以下の通りです。

列名備考
artIDintプライマリーキー
artistIDintartistテーブルのプライマリーキー値
artNamevarchar商品名
descriptionclob商品の説明
isSoldint商品が売れたかどうか
largeImagevarchar商品の画像へのパス
mediaIDintmediaテーブルのプライマリーキー値
priceint商品の価格

まずはどのようなデータがartテーブルに入っているか調べてみることにしましょう。どのようなデータが入っているか調べたい場合、cfdumpタグが便利です。cfdumpタグでは、var属性に渡した文字列や構造体・配列・クエリーなどを分かりやすい形に整形して出力してくれるタグです。

まず、{cf_root}フォルダ({cf_root}はColdFusionをインストールしたディレクトリです。Windowsでは『C:\ColdFusion8』になります)内にある『wwwroot』の中に『gihyo』という名前のフォルダを作り、その中に『3』というフォルダを作ってください。⁠3』のフォルダの中に以下のような中身のファイルをdump.cfmとして保存してください(ファイルのパスは{cfroot}/wwwroot/gihyo/3/dump.cfmになります⁠⁠。なお保存時の文字コードはUTF-8としてください。

<cfprocessingdirective pageEncoding="UTF-8" />
<cfcontent type="text/html; charset=UTF-8">
<cfquery datasource="cfartgallery" name="qry">
  SELECT
    *
  FROM
    art
  WHERE
    mediaID=2
</cfquery>
<cfdump var="#qry#">

そして、http://127.0.0.1:8500/gihyo/3/dump.cfmにアクセスすると、以下のような実行結果を得ることができると思います。

図4 cfdumpでクエリーをダンプした例
図4 cfdumpでクエリーをダンプした例

ご覧頂いて分かるとおり、cfqueryタグで生成したクエリーオブジェクト(qry)の中身が整形されてダンプされています。qry.RESULTSETの中に、実行したSQLの結果が格納されているのが分かります。その他、クエリーに関するメタデータとして、クエリーをColdFusion上でキャッシュしているかどうかのブール値(qry.CACHED⁠⁠、クエリーの実行にかかった時間(qry.EXECUTIONTIME 単位はミリ秒⁠⁠、実行したSQL文(qry.SQL)が保持されていることが分かります。また、ここにダンプされていないメタデータとして、実行したSQLで取得できたレコードの件数(qry.RecordCount)を取得することができます。このように、ColdFusionの任意のオブジェクトの中身をとりあえず知りたいという場合、cfdumpしてみるとそのオブジェクトの中身が整形されて表示されるため、オブジェクトの中身が分からず困ったときにはとりあえずcfdumpタグを使うと便利です。

さてここで、見慣れないタグとしてcfprocessingdirectiveタグcfcontentタグがあるかと思います。

cfprocessingdirectiveタグは、処理するCFMLテンプレートの文字コードが何であるかを指定するタグです。Windows環境において、ColdFusionの想定しているCFMLテンプレートの文字コードはShift_JIS(実際は類似のMS932)がデフォルトとなっています(ColdFusionを動かしているOSによってデフォルトの文字コードが異なるので注意して下さい⁠⁠。従ってShift_JISでCFMLテンプレートを作成した場合、cfprocessingdirectiveタグを省略することができます。

しかしながら、作成するアプリケーションの国際化を考えた場合、ページエンコーディングはUTF-8にするのが妥当な場合が多いので、今回はCFMLテンプレートをUTF-8で作成し、cfprocessingdirectiveタグでCFMLテンプレートの文字コードがUTF-8であると明示しています。なお、BOM(Byte Order Mark)付きUTF-8でCFMLテンプレートを作成した場合、ColdFusionはBOMからCFMLテンプレートの文字コードを判断できるため、cfprocessingdirectiveタグでの文字コードの明示は必要なくなります。

cfcontentタグは、HTTPレスポンスヘッダのContent-Typeにtype属性で指定した値を入れるようにするタグです。今回のCFMLテンプレートではUTF-8のHTMLを出力しているため、このようなMIMEタイプが入ります。

クエリーを表示してみる

cfdumpでクエリーに含まれている中身が分かったので、今度は実際にそれを整形した形で表示してみることにしましょう。

クエリーで得られた全ての行に対してループを行うにはcfloopタグを使います。cfloopタグはその名前の通り各種ループを行うためのタグです。cfloopタグのquery属性にループしたいクエリーを渡すと、そのクエリーの各行をループで取得することができます。

cfloopタグでループしているクエリーの各行のデータをHTMLに出力するにはcfoutputタグを使います。cfoutputタグで囲まれた部分のうち、シャープサイン(#)で挟まれた部分がColdFusionによって変数やプログラムとして解釈されます。

以下の例は、クエリーの各行のartNameという列の値をpタグで囲う例です。{cf_root}/wwwroot/gihyo/3/qry1.cfmとして保存し、http://127.0.0.1:8500/gihyo/3/qry1.cfmでアクセスしてみましょう。

<cfprocessingdirective pageEncoding="UTF-8" />
<cfcontent type="text/html; charset=UTF-8">
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<cfquery datasource="cfartgallery" name="qry">
  SELECT
    artName
  FROM
    art
  WHERE
    mediaID=2
</cfquery>
<title>クエリーテスト</title>
<body>
  <cfloop query="qry">
    <cfoutput><p>artName: #HtmlEditFormat(qry.artName)#</p></cfoutput>
  </cfloop>
</body>
図5 qry1.cfmの実行結果
図5 qry1.cfmの実行結果

cfoutputタグで囲まれている部分のうち、シャープサインで囲った部分はプログラムと解釈されます。今回の場合、HtmlEditFormat()という関数の引数に、qry.artName(ループしているクエリーの各行のartNameという名前の列の値)を渡して、その関数の実行結果を出力するという意味です。HtmlEditFormat()関数はHTMLの特殊な文字列(⁠⁠<」「&」など)をエスケープしてくれる関数で、これを入れておかないとXSS脆弱性などが生じるおそれがあるため、データベースのデータなどを出力する場合はこの関数を必ず使うようにしましょう。

なお、ColdFusionは変数の大文字小文字を区別しません。なので「qry.artName」「qry.ARTNAME」も同じものとして扱われます。しかしながら、データベース上のカラム名と違う名前を記述すると、後で読み返したときなどにコードが分かりづらくなることが予想されるため、データベース上と同じ綴りで記述しておくことをお奨めします。

クエリーをテーブルに出力する

上記の例よりさらに高度な例として、HTMLのテーブルにartテーブルの中身を表示してみることにしましょう。以下のプログラムを{cf_root}/wwwroot/gihyo/3/qry2.cfmとして保存し、http://127.0.0.1:8500/gihyo/3/qry2.cfmでアクセスしてみましょう。

<cfprocessingdirective pageEncoding="UTF-8" />
<cfcontent type="text/html; charset=UTF-8">
<!DOCTYPE html PUBLIC "-//W3C/DTD HTML 4.01 Transitional//EN">
<cfquery datasource="cfartgallery" name="qry">
  SELECT
    artName, description, price, isSold
  FROM
    art
  WHERE
    mediaID=2
</cfquery>
<title>ギャラリーの保有する商品の情報</title>
<body>
  <table summary="ギャラリーの保有する商品の情報">
    <tr>
      <th>商品名</th>
      <th>説明</th>
      <th>価格</th>
      <th>売約済み</th>
    </tr>
    <cfoutput>
      <cfloop query="qry">
        <tr>
          <td>#HtmlEditFormat(qry.artName)#</td>
          <td>#HtmlEditFormat(qry.description)#</td>
          <td>#NumberFormat(qry.price)#ドル</td>
          <td><cfif qry.isSold EQ 1>売約済み<cfelse>購入可能</cfif></td>
        </tr>
      </cfloop>
    </cfoutput>
  </table>
</body>
図6 qry2.cfmの実行結果
図6 qry2.cfmの実行結果

行っていることは先ほどのqry1.cfmとほぼ変わりありません。テーブルのデータ部分にループを埋め込んでいます。ご覧頂いて分かるとおり、HTMLと織り交ぜてCFMLタグを書くことができるため、見た目やHTMLの保守性という観点から、ColdFusionでHTMLベースのWebアプリケーションを作るメリットがおわかり頂けるかと思います。また、PHPのSmartyやPerlのTemplate ToolkitなどのテンプレートエンジンよりもHTMLと相性がよいことは一目瞭然でしょう。

今回はデータを表示している部分に一カ所だけ簡単なロジックを仕込みました。商品が売約済みかどうかはデータベース上では数値で持っていますが、それをそのまま出力したのでは分かりづらいものになってしまいます。従ってcfifタグでqry.isSoldの値が1だった場合「売約済み⁠⁠、そうでない場合「購入可能」という文字を表示するようにしています。cfifタグとcfelseタグは、それぞれ他の言語のif文とelse文に相当します。cfifタグ部分をPHPで書くとするなら、以下のようなコードに相当します。

if($qry['isSold'] == 1){
  echo "売約済み";
}else{
  echo "購入可能";
}

まとめと次回予告

ColdFusionはデータベースへの接続をデータソースという単位で管理していることを学びました。こうすることで、CFMLテンプレート上にデータベースの接続パスワードを書く必要がないため、HTTP経由で誤ってパスワードが漏洩してしまうリスクを軽減することができます。また、データベースにクエリーする度にデータベースサーバーのIPアドレスやアカウント情報を記述する必要がない(接続情報をColdFusion Administratorで集中管理できる)というメリットがあることが分かりました。

そして、cfdumpタグを学びました。このタグを使うことでColdFusion上の任意のオブジェクトの中身を整形した形で表示することができることが分かりました。オブジェクトの中身がよく分からず困ったときには、とりあえず何でもかんでもcfdumpする癖を付けておくと良いでしょう。

また、クエリーデータのHTMLへの出力の仕方を学びました。cfloopタグのquery属性に出力対象のクエリーを渡し、cfoutputタグとシャープマークを使ってHTML中に出力できることが分かりました。さらに、CFMLはHTMLと相性が良く、またCFML自身が他の言語でのテンプレートエンジンのような役割を果たすことから、CFMLはHTMLベースのWebアプリケーションを作成するのに適していると分かりました。

次回は動的にグラフを生成する例をご紹介します。

おすすめ記事

記事・ニュース一覧