図6●セッションを利用したショッピング・カートのサ
図6●セッションを利用したショッピング・カートのサ
[画像のクリックで拡大表示]
リスト6●商品の入力画面のHTML ファイル(sample3 )
リスト6●商品の入力画面のHTML ファイル(sample3 )
[画像のクリックで拡大表示]
リスト7 ●ショッピング・カートを実現するサーブレット「CartServlet 」(sample3 )
リスト7 ●ショッピング・カートを実現するサーブレット「CartServlet 」(sample3 )
[画像のクリックで拡大表示]
図7 ●リスト7 のCartServlet を,入出力に特化したCartServlet とカートの本体であるCart オブジ
図7 ●リスト7 のCartServlet を,入出力に特化したCartServlet とカートの本体であるCart オブジ
[画像のクリックで拡大表示]
リスト8●Cart オブジェクトを利用するよう改造したCartServlet のdoPost メソッド(sample4 )
リスト8●Cart オブジェクトを利用するよう改造したCartServlet のdoPost メソッド(sample4 )
[画像のクリックで拡大表示]
リスト9●Cart オブジェクトを生成するためのCart クラス(sample4 )
リスト9●Cart オブジェクトを生成するためのCart クラス(sample4 )
[画像のクリックで拡大表示]

ショッピング・カートでMVC を実感する

 入力したメッセージをそのまま表示するサーブレットのサンプルにはさすがに飽きてきましたね。もうちょっと実用に近いサンプルを取り上げてみましょう。セッションを利用するアプリケーションといえば何といっても「ショッピング・カート」です。

まずは一つのサーブレットでカートを実現してみる

 ショッピング・カートの基本機能は「ユーザーが入力した商品をカートに追加していく」ことです(図6[拡大表示])。これをセッション・オブジェクトを使って実現することにしましょう。

 まず,入力画面のHTMLを用意します(リスト6[拡大表示])。product1として商品1に追加したい数,product2として商品2に追加したい数をそれぞれ入力するようになっています。

 ショッピング・カートの動作を一つのサーブレットで実現したのがリスト7に示した「CartServlet」です(sample3)。中でどんな処理を行っているのか,順番に見ていきましょう。

 まず,ブラウザで入力された値をint型の配列で受け取っています*13。int型にしたのは,ブラウザで入力された数字を計算に使う必要があるからです。ただ,getParameterメソッドが返す値はStringオブジェクトです。そこで,IntegerクラスのparseIntというメソッドでint型の整数値に変換しています*14

 次にgetSessionメソッドでセッション・オブジェクトを取得しています。最初のアクセスでは,ここでセッション・オブジェクトが生成されます。

 セッション・オブジェクトに貼り付けるのは,amountという名前のIntegerオブジェクトにしました。int型の整数だと,セッション・オブジェクトに貼り付けたり取り出したりするのが面倒だからです。amountが表す数字が,カートに入っている商品の累計を表します。プログラムでは,セッション・オブジェクトから取得したIntegerオブジェクトをamountに入れています。

 最初のアクセスでは,まだセッション・オブジェクトには何もないので,amountの値はnullになります。そこで,amountがnullの場合は,「0」を表すIntegerオブジェクトを生成し,amountの値にしています。

 次の部分で,ブラウザで入力した数値(product)をamountに加算しています。Integerオブジェクトからint型の整数値を取り出すため,intValueというメソッドを使いました。こうして加算されたamountをセッション・オブジェクトに書き戻しています。

 最後に,商品の累計であるamountをHTMLで表示しています。「買い物を続ける」というリンクをクリックすると,また商品の入力ページに戻ります。入力ページで商品の数を追加すると,それに応じてカートに入っている商品の数も増えていきます。

 これで,図6のように動作するショッピング・カートのサーブレットが実現できました。カートに商品が入っている状態で一度ブラウザを終了し,もう一度アクセスしてみると,セッションが作り直されて前のデータが消えていることを確認できます。サーブレットが動作しているマシンに複数のパソコンからアクセスできる環境であれば,それぞれのパソコンごとに別のカートが用意されているのを確認できます。

入出力の制御部分とカートの本体に分割する

 このカートは,最小限の機能しか持っていません。機能を追加したくなってきますね。「在庫データベースを使って在庫管理と連動させる」といった大がかりな改造は置いておくとして,このショッピング・カートにちょっとした改良を加えたい場合,改良点は大きく二つに分かれます。「商品の数を増やしたい」「Webページの見た目をきれいにしたい」という入出力に関する改良と,「商品の数をクリアする機能を付けたい」「商品の合計金額を計算したい」といったカート本体の機能に関する改良です。

 ショッピング・カートのシステムを一人で開発している場合は,すべての機能を一つのサーブレットに詰め込んだほうが管理が楽だと思うかもしれません。しかし,サーバーサイドJavaの開発は,通常は複数の開発者が分担して行います。プログラムを機能別に分割したほうが,開発を分担しやすくなります。たとえ一人で開発する場合でも,プログラムを機能別に分けておいたほうが,バグの原因を追いかけやすくなります。

 そこで今回は,入出力の機能をサーブレットに残して,新たにカート本体を表す「Cartクラス」を作成することにしました(図7[拡大表示],sample4)。Cartクラスから生成したCartオブジェクトに商品の累計の情報を持たせ,サーブレットからアクセサ・メソッドを通してこの情報にアクセスするようにします。CartServletとCartの二つのクラスでsample3と同じ動作を実現します*15

 Cartオブジェクトを利用するように書き換えたCartServletがリスト8[拡大表示]です。sample3(リスト7)では累計を表すIntegerオブジェクトをセッション・オブジェクトに直接貼り付けていました。これに対しsample4では,Cartオブジェクトに商品の累計をint型の整数値として持たせ,Cartオブジェクトをセッション・オブジェクトに貼り付けるようにしています。このため,amountをint型の整数値として扱えるようになりました。

 ブラウザの入力データの取得やセッション・オブジェクトの取得はリスト7と同じです。セッション・オブジェクトからはCartオブジェクトを取り出すように記述します。

 初回のアクセスではCartオブジェクトは貼り付いていないので,Cartオブジェクトを表すcart変数はnullになっています。この場合,新しいCartオブジェクトを生成しています。コンストラクタには,商品の種類を引数として渡します。

 次のforループでCartオブジェクトのアクセサ・メソッドを呼び出しています。addAmountメソッドで,第1引数の番号で表される商品の累計にブラウザの入力値(product)を加算しています。次にgetAmountメソッドを使って,引数の番号で表される商品の累計を取得しています。Cartオブジェクトに対する操作が終わったら,Cartオブジェクトをセッション・オブジェクトに書き戻します。HTMLの出力部分はリスト7と同じです。
 次にCartクラスを見てみましょう(リスト9[拡大表示])。内部で商品の累計を保存する変数としてint型の配列であるamountを宣言しています。この値にクラスの外から直接触れないようにするため,アクセス修飾子はprivateにしています。

 次の部分がコンストラクタです。商品の数を引数に取り,その分の長さを持つamountの配列の領域を確保しています。最後に,累計の値を外から操作するための二つのアクセサ・メソッドを定義しています。累計を返すgetAmountメソッドは,引数が示す番号のamountを返します。もう一つのaddAmountメソッドは,第1引数が示す番号のamountに第2引数の値を加算します。