掲載誌情報
掲載誌 日経Linux 2003/02〜
タイトル リッチインターネットアプリケーションを開発しよう! 第3回
サブタイトル ColdFusion MXとFlash MXで作るリッチインターネットアプリケーションをMVCモデルで学ぶ

2. 勤怠管理システムのColdFusionコンポーネント作成
  さて、いよいよ、本連載での構築目標である勤怠管理システムについて、データベースとの連携を行うビジネスロジックをプログラミングしていく。
     
  2.1 ユーザ新規登録処理
    今回構築する勤怠管理システムで実装する各機能は、データベースに対して、登録(Insert)・参照(Select)・更新(update)・削除(delete)のいずれかのSQL文(クエリ)を発行することになるが、先ずは比較的簡単な処理である「ユーザ新規登録」の作成を通して、ColdFusion MXではどのようにデータを受け取り、どうやってデータベースに登録するかを解説する。

(1) 入力されたユーザ情報をデータベースへ登録するColdFusionコンポーネントを作成する
前回(第2回)で要件定義・仕様設計を行ったとおり、「新規ユーザ入力」機能は、ユーザ情報として、「UserID」、「Password」、「Name」、「E-Mail」をデータベースに登録する機能だ。
よって、ここでは、次のようなメソッドをもつコンポーネント「user」を作成する。
メソッドの機能としては、ユーザ情報として「UserID」、「Password」、「Name」、「E-Mail」を受け取り、それらの情報をデータベースへ格納するというものだ。
メソッド名 userRegist
処理概要 UserTableに指定情報を登録する。
引数 UserID Password Name Email
戻値 なし
リモートサーバー上に「step2」ディレクトリを作成、「step2」ディレクトリ下にファイル「user.cfc」を作成する。
更に以下のソースコードを記述し、保存する。
<cfcomponent>
 <cfprocessingdirective pageencoding="UTF-8">
 <cffunction access="remote" name="userRegist" output="false" returntype="void">
  <cfargument name="userID" type="string" required="true">
  <cfargument name="password" type="string" required="true">
  <cfargument name="name" type="string" required="true">
  <cfargument name="email" type="string" required="true">

  <cfquery name="insertUserQry" datasource="NikkeiLinux">
   INSERT INTO UserTable
   (
    UserID,
    Password,
    Name,
    Email
   )VALUES(
    '#arguments.userID#',
    '#arguments.password#',
    '#arguments.name#',
    '#arguments.email#'
   )
  </cfquery>
(A)

  <cfreturn>
 </cffunction>
</cfcomponent>
(A)の処理がデータベースの操作を行っている部分である。
ColdFusionでデータベースを操作するには「cfquery」タグを用いる。

「cfquery」タグを使用したデータベース操作でポイントになるのは次の点だ。
「datasource」属性へのDSN指定
  datasource属性には、前回(第2回)「ColdFusion MXでのDSN設定を行う」で設定したDSN(Data Source Name)※注1を指定する。この設定により、指定したデータベースへのアクセスが可能になる。
「cfquery」タグ内にSQL文を記述
  <cfquery>〜</cfquery>タグ間に、データベースに発行するSQL文を記述する。

※注1 データベースにMySQLを利用する場合、DSNの設定で、接続文字列を指定しておく必要がある。
設定方法は下記のようになる。
  1. ColdFusion MXの管理画面にログインする
  2. 管理画面トップ左側のナビゲーションから「データソース」を選択する。
  3. 使用するデータソース名をクリックする。
  4. [詳細設定の表示]ボタンを押して、詳細設定画面を開いた後「接続文字列」の部分に「useUnicode=true&characterEncoding=euc-jp」と記述する。
上記、「euc-jp」の部分はMySQLで使用している文字コードとなる。読者の環境に合わせて適宜読み換えていただきたい。
  5. 送信ボタンをクリックする。

さて、SQL文であるが、今回の場合、テーブル「UserTable」の各フィールドにレコードを挿入するため、次のようになる。
INSERT INTO UserTable (UserID, Password, Name, Email)
VALUES ('設定値', '設定値', '設定値', '設定値')
ソースコードでは、上記 「ユ設定値ユ」 の部分が「'#arguments.userID#'」のようになっているが、これはメソッドの引数である「arguments.userID」変数だ。
このように、SQL文中に「#」で囲んだ変数名を記述することで、動的なSQL文の実行が可能となる。
(2) 新規ユーザ入力ページの作成
次に、(1)で作成した「user.cfc」の動作を確認するため、Web上の「新規ユーザ入力」ページから入力を行い、入力情報をデータベースに格納する簡易アプリケーションを作成してみる。
「step2」ディレクトリ下に、ユーザ情報を入力するページ「registForm.cfm」、および、入力された情報をデータベースへ登録し、完了メッセージを表示するページ「registUser.cfm」を作成する。
ソースコードはそれぞれ次のようになる。

「registForm.cfm」
<cfprocessingdirective pageencoding="UTF-8">
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>日経Linuxサンプル</title>
</head>
<body>
 <center>
 <form name="myForm" method="post" action="registUser.cfm">
 <table border="0" cellpadding="0" cellspacing="0" width="300">
  <tr>
   <td width="100">UserID</td>
   <td width="200"><input name="fmUserID" type="text" size="20"></td>
  </tr>
  <tr>
   <td>Password</td>
   <td><input name="fmPassword" type="text" size="20"></td>
  </tr>
  <tr>
   <td>Name</td>
   <td><input name="fmName" type="text" size="20"></td>
  </tr>
  <tr>
   <td>E-Mail</td>
   <td><input name="fmEmail" type="text" size="20"></td>
  </tr>
 </table>
 <br>
 <input type="submit" value="登録">
 </form>
 </center>
</body>
</html>
これは、HTMLのformを配置し、登録ボタンがクリック(submit)されたら、「registUser.cfm」にリンクするページとなる。

「registUser.cfm」
<cfprocessingdirective pageencoding="UTF-8">

<cfset setEncoding("Form","UTF-8")> (A)

<cfinvoke component="user" method="userRegist">
 <cfinvokeargument name="userID" value="#Form.fmUserID#">
 <cfinvokeargument name="password" value="#Form.fmPassword#">
 <cfinvokeargument name="name" value="#Form.fmName#">
 <cfinvokeargument name="email" value="#Form.fmEmail#">
</cfinvoke>
(B)

<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>日経Linuxサンプル</title>
</head>
<body>
 <center>
 ユーザの登録が完了しました。
 </center>
</body>
</html>
これは、「registForm.cfm」から渡されたform変数の情報をデータベースへ登録し、結果を表示するページとなる。
実処理としては、(B)の部分で、先程作成したColdFusionコンポーネントを呼び出しているだけである。
なお、(A)の部分では、「registForm.cfm」から受け取ったform変数をColdFusion内で正常に処理できる様、form変数の文字コードをエンコードしている。
(3) 作成したページにアクセスしてみる
ブラウザを起動して「http://<ホスト名またはIPアドレス>/step2/registForm.cfm」にアクセスする。
ユーザ情報を入力したら、「登録」ボタンをクリックする。

スクリーン
正常に登録できたら、次の画面が表示される。
スクリーン
MySQLでUserTableを確認してみると、実際にレコードが追加されているはずだ。
これで、ユーザ情報の登録が行えるようになったが、この登録ページを他の人が利用すると考えた場合、利用するユーザがいつも正しくデータを入力するとは限らない。
やはり、最低限の入力チェックは必要となるだろう。そこで、次に入力チェック機能を組み込んでみる。
(4) 入力チェック機能を組み込む
ここでは、先程作成したColdFusionコンポーネントに以下の入力チェックを追加する。
・入力項目に1つでも未入力の項目がある場合はエラーとする。
・UserID、Passwordは半角英数字で入力された場合のみ登録を受け付ける。
・入力されたUserIDが既にデータベースに登録済みの場合はエラーとする。

「user.cfc」を次の様に修正する。
<cfcomponent>
 <cfprocessingdirective pageencoding="UTF-8">

 <cffunction name="userRegist" access="remote" returnType="string" output="false"> (A)

  <cfargument name="userID" type="string" required="true">
  <cfargument name="password" type="string" required="true">
  <cfargument name="name" type="string" required="true">
  <cfargument name="email" type="string" required="true">

  <!--- 未入力チェック --->
  <cfif arguments.userID EQ "" OR arguments.password EQ "" OR arguments.name EQ "" OR arguments.email EQ "">
   <cfreturn "未入力の項目があります。全ての項目を入力してください。"> (A)
  </cfif>
(B)

  <!--- 半角英数字チェック --->
  <cfif REFindNoCase("^[A-Za-z0-9]+$",arguments.userID) IS 0 OR REFindNoCase("^[A-Za-z0-9]+$",arguments.password) IS 0>
   <cfreturn "UserID、Passwordは半角英数字で入力してください。"> (A)
  </cfif>
(C)

  <!--- UserID重複チェック --->
  <cfquery name="checkUserQry" datasource="NikkeiLinux">
   SELECT UserID FROM UserTable WHERE UserID = '#arguments.userID#'
  </cfquery>
  <cfif checkUserQry.RecordCount GT 0>
   <cfreturn "UserIDが重複しています。別のUserIDを入力してください。"> (A)
  </cfif>
(D)

  <!--- User情報登録 --->
  <cfquery name="insertUserQry" datasource="NikkeiLinux">
   INSERT INTO UserTable
   (
    UserID,
    Password,
    Name,
    Email
   )VALUES(
    '#arguments.userID#',
    '#arguments.password#',
    '#arguments.name#',
    '#arguments.email#'
   )
  </cfquery>

  <cfreturn ""> (A)
 </cffunction>
</cfcomponent>
ここでのポイントは次のとおりである。
(A) ColdFusionコンポーネントの実行結果を、呼出元へ返す。
入力チェックの結果、エラーである場合は実行結果としてエラーメッセージを返すようにする。(正常にデータベースへの登録を行った場合は、空文字を返す)
また、戻値として文字列を返すようにするため、「cffunction」タグの「returnType」属性を「string」としている。
(B) 未入力チェックを行う。
各引数の値をチェックし、空文字(「モモ」)でないかをチェックする。
条件判定には「cfif」タグを用いる。結合演算子「OR(または)」は、複数の条件式を組み合わせる際に使用する。
(C) 半角英数字チェックを行う。
引数UserID、Passwordの値をチェックし、半角英数字であるかをチェックする。
半角英数字であるかどうかは、「REFindNoCase」関数を用いて判別することができる。
「REFindNoCase」関数の使用方法は、ColdFusion MXのリファレンスマニュアルを参考にしていただきたい。
(D) UserIDの重複チェックを行う。
入力されたUserIDがデータベースに登録済みであるかどうかは、次のSQL文を実行し、返されたレコードの件数を調べることで判別可能だ。
レコード件数が、0件であれば指定したUserIDはまだ登録されていないことになる。
SELECT UserID FROM UserTable WHERE UserID = 'チェックするUserID'
したがって、CFMLでの記述は次のようになる。
<cfquery name="checkUserQry" datasource="NikkeiLinux">
 SELECT UserID FROM UserTable WHERE UserID = '#arguments.userID#'
</cfquery>
<cfif checkUserQry.RecordCount GT 0>
 <cfreturn "UserIDが重複しています。別のUserIDを入力してください。">
</cfif>
SQL文を実行し、データベースから返されたレコード情報は「cfquery」タグの「name」属性で指定した変数に全て格納される。この変数はクエリ変数と呼ばれ、今まで登場した変数とは異なり、単一の値ではなく、複数の情報を持っている。
レコード件数は、「クエリ変数名. RecordCount」と記述することで参照可能だ。
上記ソースコードでは、レコード件数が0件より大きいかを判定している。

「registUser.cfm」を次の様に修正する。
<cfprocessingdirective pageencoding="UTF-8">
<cfset setEncoding("Form","UTF-8")>

<cfinvoke component="user" method="userRegist" returnvariable="ret"> (A)
 <cfinvokeargument name="userID" value="#Form.fmUserID#">
 <cfinvokeargument name="password" value="#Form.fmPassword#">
 <cfinvokeargument name="name" value="#Form.fmName#">
 <cfinvokeargument name="email" value="#Form.fmEmail#">
</cfinvoke>

<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>日経Linuxサンプル</title>
</head>
<body>
 <center>

 <cfif ret EQ "">
  ユーザの登録が完了しました。
 <cfelse>
  <cfoutput>#ret#</cfoutput>
 </cfif>
(B)

 </center>
</body>
</html>
ここでのポイントは次のとおりである。
(A) ColdFusionコンポーネントからの実行結果を受け取る。
実行結果は「cfinvoke」タグの「returnvariable」属性に指定した変数に格納される。
(B) 実行結果に応じて、ブラウザに表示するメッセージを切り替える。
ここでは、実行結果が正常である場合は、完了メッセージを、異常である場合は、エラーメッセージ(ColdFusionコンポーネントから返されたメッセージ)を表示している。

これで入力チェックの追加は完了だ。
  2.2 ユーザ一覧参照機能
    次に、今度は先程登録したユーザ情報をデータベースから取り出し、ユーザ一覧を表示する簡易アプリケーションを作成してみる。

(1) ユーザ情報をデータベースから取得するColdFusionコンポーネントを作成する。
ここでは、次の機能をもつメソッドを作成する。
メソッド名 userListGet
処理概要 UserTableからユーザ一覧情報を取得し、取得データを返す。
引数 なし
戻値 クエリ
尚、ユーザ情報を取得するメソッドおよび、2.1で作成したユーザ情報を登録するメソッドは、共にユーザ情報を管理するという共通の目的をもったメソッドだ。よって、両メソッドはユーザ情報管理コンポーネントとして、1つのコンポーネントにまとめた方が分かりやすい。
したがって、ここで作成するメソッドは、「user.cfc」に追加することにする。

「user.cfc」を次のように追加修正する。
<cfcomponent>
 <cfprocessingdirective pageencoding="UTF-8">
 <cffunction name="userRegist" access="remote" returnType="string" output="false">
  <cfargument name="userID" type="string" required="true">
  <cfargument name="password" type="string" required="true">
  <cfargument name="name" type="string" required="true">
  <cfargument name="email" type="string" required="true">
    ・・・省略・・・
  <cfreturn "">
 </cffunction>

 <cffunction name="userListGet" access="remote" returnType="query" output="false">

  <cfquery name="selectUserQry" datasource="NikkeiLinux">
   SELECT UserID, Password, Name, Email
   FROM UserTable
  </cfquery>
(A)

  <cfreturn selectUserQry>
 </cffunction>
(B)
追加する
メソッド

</cfcomponent>
ここでのポイントは次のとおりである。
(A) データベースからユーザ情報を取得する。
UserTableから全てのユーザ情報を取得するには、次のSQL文を実行する。
したがって、<cfquery>タグを用いて、下記SQL文を指定している。
SELECT UserID, Password, Name, Email FROM UserTable
SQL文を実行し、データベースから返されたレコード情報は「cfquery」タグの「name」属性で指定した「selectUserQry」クエリ変数に、全て格納される。
(B) データベースから取得した情報を、呼出元へ返す。
「cfreturn」タグで変数「selectUserQry」を指定することで、レコード情報が全て呼び出し元に返される。
また、戻値としてクエリ変数を返すようにするため、「cffunction」タグの「returnType」属性を「query」としている。
クエリ変数を用いたレコード情報への参照方法は次のプログラムで説明する。
(2) ユーザ情報一覧ページの作成
次に、(1)で作成した「user.cfc」の動作を確認するため、ユーザ情報一覧ページを作成する。
「step2」ディレクトリ下に、「listUser.cfm」を作成する。
ソースコードは次のようになる。
<cfprocessingdirective pageencoding="UTF-8">

<cfinvoke component="user" method="userListGet" returnvariable="ret"> (A)

<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>日経Linuxサンプル</title>
</head>
<body>
 <center>
 <table border="1" cellpadding="0" cellspacing="0" width="600">
  <tr>
   <td width="150" align="center">UserID</td>
   <td width="150" align="center">Password</td>
   <td width="150" align="center">Name</td>
   <td width="150" align="center">E-mail</td>
  </tr>

  <cfoutput query="ret">
  <tr>
   <td>#ret.UserID#</td>
   <td>#ret.Password#</td>
   <td>#ret.Name#</td>
   <td>#ret.Email#</td>
  </tr>
  </cfoutput>
(B)

  </tr>
 </table>
 </center>
</body>
</html>
ここでのポイントは次のとおりである。
(A) ColdFusionコンポーネントからの実行結果を受け取る。
実行結果は「cfinvoke」タグの「returnvariable」属性で指定した変数に格納される。
よって、データベースから取得したレコード情報がクエリ変数「ret」に格納されることになる。
(B) 返されたユーザ情報を表示する。
レコード情報を全て出力するには、「cfoutput」タグを用い、「query」属性にクエリ変数を指定する。
すると、データベースから返されたレコード毎に「cfoutput」で囲まれた全てのコードが繰り返し出力される。
データベースから返された任意のフィールドを指定するためには、「クエリ変数名.フィールド名」と記述する。
  2.3 タイムカード出社打刻機能
    続いて、出社時のタイムカード出社打刻に必要なColdFusionコンポーネントの実装を行う。
タイムカード出社打刻機能は、ユーザが入力した「UserID」、「Password」を基にユーザを特定し、出社記録を行う機能だ。
出社打刻の流れは前回(第2回)にも登場した下記アクティビティ図のとおりとなる。
 (図:uml/アクティビティ図.pdf)
したがって、次のようなメソッドをもつコンポーネントを作成する。
メソッド名 commingStamp
処理概要 チェック結果が正常な場合、TimecardTableに出社打刻情報を登録する。
引数 UserID Password
戻値 エラーメッセージ
「step2」ディレクトリ下にファイル「timecard.cfc」を作成し、次のソースコードを記述する。
<cfcomponent>
 <cfprocessingdirective pageencoding="UTF-8">
 <cffunction name="commingStamp" access="remote" returnType="string" output="false">
  <cfargument name="userID" type="string" required="true">
  <cfargument name="password" type="string" required="true">

  <!--- 入力チェック --->
  <cfif arguments.userID EQ "" OR arguments.password EQ "">
   <cfreturn "UserID、Passwordを入力してください。">
  </cfif>
(A)

  <!--- UserID、Password妥当性チェック --->
  <cfquery name="checkUserQry" datasource="NikkeiLinux">
   SELECT * FROM UserTable
   WHERE UserID = '#arguments.userID#'
   AND Password = '#arguments.password#'
  </cfquery>
  <cfif checkUserQry.RecordCount EQ 0>
   <cfreturn "UserID、またはPasswordが誤っています。">
  </cfif>
(B)

  <!--- 出社済みチェック --->
  <cfquery name="checkTimecardQry" datasource="NikkeiLinux">
   SELECT * FROM TimecardTable
   WHERE UserID = '#arguments.userID#'
   AND TargetDay = CURDATE();
  </cfquery>
  <cfif checkTimecardQry.RecordCount NEQ 0>
   <cfreturn "本日は、既に出社打刻されています。">
  </cfif>
(C)

  <!--- タイムカードテーブルへ登録 --->
  <cfquery name="insertTimecardQry" datasource="NikkeiLinux">
I   NSERT INTO TimecardTable
   (
    UserID,
    TargetDay,
    ComingTime,
    QuittingTime
   )VALUES(
    '#arguments.userID#',
    CURDATE(),
    CURTIME(),
    NULL
   )
  </cfquery>
(D)

  <cfreturn "">
 </cffunction>
</cfcomponent>
ここでのポイントは次のとおりである。
(A) 未入力チェックを行う。
UserID、Passwordが未入力でないかチェックを行っている。
(B) UserID、Passwordが登録されたユーザのものであるかチェックを行う。
入力されたUserID、Passwordが登録ユーザのものであるか否かは、UserTableに該当するレコードが存在するか否かで判別可能だ。
(C) 対象日に既に出社打刻を行っていないかチェックを行う。
同一ユーザが既に出社打刻を行っているか否かは、対象ユーザ、対象日のレコードがTimecardTableに存在するか否かで判別可能だ。
(D) TimecardTableへデータを登録する。
全てのチェックが正常である場合は、TimecardTableテーブルへレコードを挿入する。
  2.4 その他の機能
    勤怠管理システムでは他にも以下のような機能を実装予定としている。
タイムカードの退社打刻機能
ユーザが入力した「UserID」、「Password」を基にユーザを特定し、退社記録を行う。
タイムカードの月次参照機能
ユーザの月別出退社時間を一覧表示する。
ユーザ情報更新機能
登録ユーザの情報を更新する。
ユーザ情報削除機能
登録ユーザの情報を削除する。
したがって、これらの機能を全て実装したColdFusionコンポーネントは、以下のようなものになる。

○「timecard」コンポーネント
提供メソッド commingStamp
処理概要 チェック結果が正常な場合、TimecardTableに出社打刻情報を登録する。
引数 UserID Password
戻値 エラーメッセージ
提供メソッド quittingStamp
処理概要 チェック結果が正常な場合、TimecardTableに退社打刻情報を登録する。
引数 UserID Password
戻値 エラーメッセージ
提供メソッド getTimecard
処理概要 チェック結果が正常な場合、TimecardTableに退社打刻情報を登録する。
引数 UserID 対象年 対象月
戻値 取得レコード

○「user」コンポーネント
提供メソッド userRegist
処理概要 UserTableに指定情報を登録する。
引数 UserID Password Name Email
戻値 エラーメッセージ
提供メソッド userListGet
処理概要 UserTableからユーザ一覧情報を取得し、取得データを返す。
引数 なし
戻値 クエリ
提供メソッド userDetailGet
処理概要 UserTableからユーザ詳細情報を取得し、取得データを返す。
引数 UserID
戻値 クエリ
提供メソッド userUpdate
処理概要 UserTableの特定Userの情報を更新する。
引数 UserID Password Name Email
戻値 エラーメッセージ
提供メソッド userDelete
処理概要 UserTableから特定Userの情報を削除する。
引数 UserID
戻値 -
各コンポーネントの詳細は、ここでは割愛させていただくが、付録にソースコードを含めているのでそちらを参照して欲しい。

いよいよ次回(最終回)は、今回作成した勤怠管理システムのバックオフィスと、FlashMXで作成したユーザインターフェースを連動させることでリッチインターネットアプリケーションへとグレードアップを行う予定である。

BACK  
PAGETOP
CLOSE