前回は、ログイン処理の実装とセッションスコープについて学びました。

属性を扱うのも2つ目でしたから、その概念には慣れてきたのではないでしょうか?

今回は、JavaBeansについて学びます。

1. JavaBeansとは

JavaBeansとは再利用可能なJavaプログラムの部品です。

Javaというネーミングはそもそもジャワコーヒーから来ているのですが、その豆【Beans】ということで部品という意味です。ひとまずはデータを入れる箱とお考えください。

JSPのELと相性が良いのがこのJavaBeansなのです。


ここでもまた、数あてゲームについて考えてみましょう。

2章で見た数当てゲームの概念図を再掲すると下図6.1の通りでした。

本当はリクエスト属性にはインスタンスが入るにも関わらず、文字列と数値をそれぞれ入れていましたね。

kazuate1
図6.1 第2章の数当てゲーム

まずは、これを下図6.2に変えます。

これを今回「属性にオブジェクトを入れるがJavaBeansは使わないケース」と呼びたいと思います。すなわち、リクエスト属性には1つのインスタンスだけを入れて持ち運ぶこととします。それに伴い、ELの表記が変化する点にもご注目ください。

kazuate2
図6.2 リクエスト属性にはインスタンスを入れるようにした
  • 違い探しクイズ 図6.2は図6.1とどこが違いますか?(ヒント:2箇所違います)
あなたの答え:

そしてさらにJavaBeansを使うことで最終形態の下図6.3に変えます。ここでもまた、ELの表記が変化した点に注目ください。

kazuate_javaBeans
図6.3 JavaBeanを使った数当てゲーム
  • 違い探しクイズ 図6.3は図6.2とどこが違いますか?(ヒント:1箇所違います)
あなたの答え:

1.1 2章で解説した数当てゲーム(再掲)

復習ですので以下の4つのファイルを使ってどのようなことをしているか説明してください。

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>index.html</title>
    </head>
    <body>
        <h3>0-9の整数で数を当ててください!</h3>
        <form method="get" action="/03_JavaWebText/GameServlet">
            <input type ="text" size ="10" name ="guess">
            <button type="submit">送信</button>
        </form>
    </body>
</html>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>result.jsp</title>
    </head>
    <body>
        <h1>ゲームの結果は!</h1>
        ${message}<br>
        答えは${answer}<br>
    </body>
</html>

1.2 属性にオブジェクトを入れるがJavaBeansは使わないケース

2章で解説した数当てゲームでは上図6.1 のとおり、リクエスト属性には2つのインスタンス(String型の文字列とInteger型の整数)を入れていました。しかし、この後、例えば、データベースで扱ったCustomerを扱うような場合に、名前、メールアドレス、住所、誕生日やポイント数などテーブルの列数だけインスタンスを属性に詰め込まなければいけないとしたら大変です。

顧客一人分のすべての情報を持ったCustomerクラスを一度にJSPに送って表示できたら便利だと思いませんか?

さらには複数のCustomer(今井さん、篠原さん、田渕さん、坂野さんなど)のデータの入ったCustomersクラスがあって、データベースから全員分データを取得して一度にJSPに送って表示できるとしたらどうでしょうか?

そこで、リクエスト属性にはオブジェクトをまるごと入れるというのが前述の図6.2でした。

以下にそれをソースコードで実現します。

そのためには、kazuateクラスを以下のようにkazuateObjectクラスに変えます。

  • kazuate.javaとkazuateObject.javaを比較した場合フィールドの観点での変更点は何ですか?
あなたの答え:
  • 同様にメソッドの観点での変更点は何ですか?
あなたの答え:

answerとmessageをフィールドとしてインスタンス自身が持ち運ぶようにしたわけですね。

サーブレットは以下GameServlet5.javaのようになります。

JSPは以下result1.jspのようになります。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>result1.jsp</title>
    </head>
    <body>
        <h1>ゲームの結果は!</h1>
        ${kazuate.getMessage()}<br>
        答えは${kazuate.getAnswer()}<br>
    </body>
</html>

EL式でインスタンスのメソッドを呼び出しています。これがこの後、JavaBeansを使うことでどのように変わるかに期待してください。

特に新しい論点はありませんが、入力画面のindex1.htmlを以下に掲載します。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>index1.html</title>
    </head>
    <body>
        <h3>0-9の整数で数を当ててください!</h3>
        <form method="get" action="/03_JavaWebText/GameServlet5">
            <input type ="text" size ="10" name ="guess">
            <input type ="submit" value ="送信">
        </form>
    </body>
</html>

1.3 JavaBeansを使うケース

まず最初に結論としてJavaBeansを使った場合のソースコードを紹介します。

以下のKazuateBean.javaはモデルです。

今までのKazuateObjectクラスとの変更点を見ましょう。

  • 実装しているインタフェースの観点での変更点は何ですか?
あなたの答え:

JavaBeansがJavaBeansであるためには以下の3つのルールを適用する必要があります

  • java.io.Serializableを実装している
  • 引数のないコンストラクタを持つ
  • フィールドはprivateにした上でプロパティへのgetter/setterメソッドを持つ

以下に順を追って解説します。

1.3.1 JavaBeansはjava.io.Serializableを実装している

Serializableインタフェースを実装することでスコープ内のインスタンスを直列化してファイルに保存することができるようになります。

インスタンスを直列化してファイルに保存できれば、

  • GlassFish等のアプリケーションサーバーが停止した場合も再起動してインスタンスを復元できます
  • 一時的にメモリが溢れた場合にも退避させることができます

なお、 Serializableインタフェースはマーカーインターフェイスだということを忘れてしまった方はJavaSEのインタフェースのところで復習しておいてください。

1.3.2 JavaBeansは引数のないコンストラクタを持つ

今回のKazuateBeanクラスでは、たまたま引数のないコンストラクタがありましたので特に変更点はありません。

「コンストラクタの無いJavaクラスには見えてないけれどデフォルトコンストラクタがあるはず」そう思った方はコンストラクタの事がよく分かっています。

その場合はデフォルトコンストラクタで結構です。

しかし、もしも引数のあるコンストラクタを作った場合はデフォルトコンストラクタは作られません。

その場合は引数のないコンストラクタをあらためて作る必要があります。

1.3.3 JavaBeansはフィールドはprivateにした上でプロパティへのgetter/setterメソッドを持つ

上記のKazuateBeanクラスには2つのフィールド(answerとmessage)がありました。

getter/setterメソッドとは、getXxxx、setXxxx としたフィールドにアクセスするためのメソッドのことです。

(上記KazuateBeanのgetAnswer()がその例になります)

プロパティというのはこのメソッドの Xxxxの最初を小文字にしてxxxxとしたものです

(後で見るresult2.jspのkazuate.messageがその例です)

プロパティ化したいメソッド名の先頭にはget/setを付けるというルールがあります

(本当はxxxのところにはフィールド名以外が来てもよいのですが、当社の新人エンジニア研修ではメソッドのXxxxのところには全てフィールド名を入れることにしますので、その限りにおいてフィールドとプロパティの間に特段の区別は必要ありません)


なお、getter/setterメソッドはアクセサメソッド【accessor methods】と総称されることもあります。

アクセサメソッドでは単にフィールドの値を設定取得するだけでなく、加工することもできます。

アクセサメソッドはIDEを使っていれば簡単に挿入できますので方法を講師にお尋ねください。

フィールドを private で修飾するとクラス外からはアクセスできなくなるということを我々はカプセル化と情報隠蔽のところで学びました。そこでアクセサメソッドを使ってフィールドにアクセスします。


ここである程度勉強している人は「情報隠蔽をしてもアクセサメソッドがあれば同じではないか?」と考えるかも知れません。しかし、思い出していただきたいのですが、int型のフィールドにはint型の値であれば何でも入ったのに対して、メソッドを経由すれば、特定の値(例えば、マイナスの値)は入らないようにすることもできましたね。さらに、読み込みだけ可能で、一切書き込みができないクラスを作りたいのであれば、setterメソッドを作らなければよいのです。

なお、このプロパティの考え方は他のオブジェクト指向言語にも発展的に採用されています。例えばC#、Python、Kotlin等のプロパティはより便利に使えるようになっています。

※なお、先のJavaBeansを使用していないKazuateObjectクラスのようなオブジェクトを昔ながらの普通のオブジェクトという意味でPOJO【Plain Old Java Object】と呼ぶことがあります。

2. JavaBeansを活用した数あてゲーム

では、早速Beansを使ったプログラムがどう変わるかを見てみましょう。

入力画面<index2.jsp>は<index1.jsp>から飛び先以外大きな変更はありません。

以下のGameServlet6.javaを読み込んで質問に答えてください。

  • 21行目でリクエストスコープに格納しているのは何ですか?
あなたの答え:

以下のresult2.jspはゲームの結果を表示するビューです。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>result2.jsp</title>
    </head>
    <body>
        <h1>ゲームの結果は!</h1>
        ${kazuate.message}<br>
        答えは${kazuate.answer}<br>
    </body>
</html>

このELで利用しているのがプロパティです。

プロパティを使ったELの書式

${オブジェクト名.プロパティ名}

kazuate.messageと書くことによってkazuateクラスのインスタンスのgetMessageメソッドが働くのです。

  • では、${kazuate.answer}という記述によって働くのはどのクラスの何というメソッドですか?
あなたの答え:

例題1

以下のCustomersBean.javaというJavaBeansを使って、サーブレットでインスタンスを作成し、JSPで内容を表示させなさい。

なお、toStringメソッドを忘れてしまった方はJavaSEに戻って「toStringメソッドで出力内容をコントロールする」というテーマを復習してください。

<CustomerServlet.java>を作成してください。

下図のイメージの<show_customer.jsp>を作成してください。

図6.3 出力イメージ

実験1

上記 <show_customer.jsp> に以下のようなELを書き入れた場合どのような表示になりますか?

${customer}

実験結果のメモ:

この事実はテストする際に有効であることを銘記してください。

例題2

例題1のCustomerBeanのリストをフィールドに持つ、以下のCustomersBean.クラスを使ってサーブレットでインスタンスを作成し、JSPで内容を表示させなさい。

なお、出力は以下のshow_customers.jspを使うこと。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>show_customers.jsp</title>
    </head>
    <body>
        <h1>顧客情報</h1>          
       ${customers}
    </body>
</html>

出力は以下図6.4の通りです。

顧客情報
図6.4 出力イメージ

※この表示を綺麗にしたい方は次章までお待ち下さい。

3. 買い物かごの実装

ここまでの知識を応用して買い物かごの仕組みを作ってみましょう。

どんな知識を使うかといえば主にセッション属性とJavaBeansです。

目指したいのは下図6.4のような仕組みです。

ポイントは赤で表示されたcartオブジェクトです。このオブジェクトには複数のcarオブジェクトが入るとします。カートの合計金額はどのオブジェクトが持つべきでしょうか?

そうですね、個々の車に持たせるのは変ですからcartが持つべきでしょうね。また、このcartは車の追加や削除ができないといけません。

セッション属性を使ったカートの仕組み
図6.4 セッション属性を使ったカートの仕組み

以下のCarBean.javaは車のクラスです。セッションスコープに入れることを見越してBeansとして作成します。特に特徴のないアクセサメソッドを持つBeansですが、このあとの説明のためインスタンスを1行で作れるように引数を2つ持つコンストラクタも作成しておきました。

CarBeanクラス

Cartクラス

以下のCart.javaを読み込んで質問に答えてください。

  • このCartクラスのフィールドとメソッドのそれぞれの役割を答えなさい。
あなたの答え:



削除のメソッドにはイテレータというものを使っています。

なぜ、イテレータが必要なのかという点に関しては詳細は皆さんに余裕があるようであれば講師から説明します。


以下のCartSample1.javaを読み込んで質問に答えてください。

  • 上記の処理を解説しなさい。
あなたの答え:



これをサーブレットとJSPを使って実現できればよいわけですね。

そのためにはJSPに繰り返しや条件分岐を使って表示できたほうが良いので先にJSTLなどを学ぶことにします。

この章ででてきたCustomerクラスやCustomersクラス、CarクラスやCartクラスは次の章でも使いますので、しっかり復習しておいてください。


今回はJavaBeansについて学びました。

次回はELとJSTLで様々な表現ができるようになる方法を学びます。

まとめ

□ JavaBeansとは再利用可能なJavaプログラムの部品であり、リクエスト/セッションスコープと相性が良い

□ JavaBeansには①java.io.Serializableを実装している②引数のないコンストラクタを持つ③フィールドはprivateにした上でプロパティへのgetter/setterメソッドを持つという3つのルールがある

□ プロパティ化したいメソッド名の先頭にget/setを付けるというルールがある

□ プロパティはアクセサメソッドのget/setXxxxの最初を小文字にしてxxxxとしたものである

□ ELでプロパティを扱う場合の書式:${オブジェクト名.プロパティ名}