簡易書籍一覧表示アプリケーションの説明(JPA版)

6.4 簡易書籍一覧表示アプリケーションの説明(JPA版)

6.3で作成したアプリケーションをもとに、JPAを利用したデータベースアクセス処理が実際どのような流れで動作しているのかを説明していきます。

6.4.1 Bookクラス(エンティティクラス)

まず初めに、今回新たに登場したエンティティクラスから確認していきましょう。

JPAを利用する場合、データベースのデータとなる部分は「エンティティ」(Entity)クラスとして定義されます。データベースは通常、データベース内にテーブルを定義し、そこにレコードとしてデータを保管していきますが、エンティティはこの1つ1つのレコードをJavaオブジェクトとして保管したもの、と考えるとよいでしょう。

テーブルから必要なレコードを取り出したりすると、それはJPAではエンティティクラスのインスタンスの形になっている、というわけです。またレコードを追加する場合も、エンティティクラスのインスタンスを作り、それを永続化する処理を行なえば、JPAによりそのオブジェクトの内容がレコードとしてテーブルに保管されるのです。
では、エンティティクラスはどのように作成されるのでしょうか。その基本形を整理すると以下のようになるでしょう。

■エンティティクラスの基本形

エンティティクラスは、非常に単純です。これはごく一般的なPOJO(Plain Old Java Object、何ら継承も依存関係もないシンプルなJavaオブジェクト)なのです。注意点は1つだけ。クラス定義の前に「@Entity」というアノテーションを付けるだけです。
エンティティには、保管する値をフィールドとして用意します。通常はprivateフィールドとして定義し、それぞれにアクセサメソッドを用意します。それ以外の特別なものは何も必要ありません。

ただ、実際に作成した「Book.java」を見てみると、「単純なPOJOクラス」といった割には見覚えのないimport文がずらりと並んでいますが、これらはクラス内に記述されているアノテーションのためのものです。クラスそのものは単純なのですが、アノテーションを使ってクラスやフィールドに関する細かな情報を指定しているのですね。
では、ここで使われているアノテーションについてまとめておきましょう。

■@Entity
既に説明してしまいましたが、エンティティクラスであることを示すアノテーションです。エンティティクラスでは必ず記述します。

■@Table(name=”bookinfo”)
このエンティティクラスに割り当てられるテーブルを指定します。Nameでテーブル名を指定します。実は、これは省略しても構いません。その場合はクラス名がそのままテーブル名として認識されます。

■@Id
プライマリーキーを指定します。エンティティクラスを定義する際には、必ず用意しておくようにしましょう。

■@Column
フィールドに割り当てられるカラム名を指定します。省略可能です。省略した場合には、フィールド名がそのままカラム名として使われます。
このアノテーションには、フィールドに関するいくつかの引数が用意できます。ここでは以下のようなものを使っています。

ざっと見ればわかるように、@Entity や @Id は必須の項目であり、@Table や @Column は今回のように既にあるテーブルにエンティティを割り当てるような場合に使うものと考えるとよいでしょう。

これでエンティティはできました。ですが、エンティティはテーブルに保管されるデータをJava内でオブジェクトとして扱えるようにするためのクラスであり、これだけでデータベースアクセスが完成するわけではありません。別途、データベースアクセスに必要な処理をいろいろと用意する必要があります。

これには、さまざまなアプローチがあります。今回は、Spring Bootを利用するメリットが最大限感じられる「リポジトリ」を使った方法から見ていきましょう。

6.4.2 BookRepositoryインターフェース(リポジトリクラス)


リポジトリ」は、データベースアクセスのための基本的な手段を提供します。これは通常、インターフェースとして用意されます。ですが、それをimplementsしたり、実装クラスを定義したりする必要はありません。クラスは実装しないし、処理も書かないのです。

リポジトリは、汎用的なデータベースアクセスの処理を自動的に生成し、実装してくれます。
このため、今回もほとんどコードを書くことなくデータベースアクセスが行なえるようになったはずです。

インターフェース自体は、JpaRepository<Book, String> というクラスを継承しています。この、「JpaRepository」というクラス(正確にはインターフェース)は、新たにリポジトリを作成する際の土台となるものです。すべてのリポジトリは、このJpaRepositoryを継承して作成されます。
「<Book, String>」という指定により、このリポジトリの対象となるエンティティクラスが Book であり、プライマリーキーとなるのが String型 の値であることが指定されています。

この BookRepository インターフェースの中に、必要に応じてメソッドを定義していく方法もあるのですが、今回は空っぽの状態で進めていきます。

■Repositoryアノテーション
BookRepositoryでは、JpaRepositoryを継承するほかにも重要なポイントがあります。それは、@Repositoryアノテーションです。
この@Repositoryアノテーションは、このクラスがデータアクセスのクラスであることを示します。@Controllerアノテーションなどと同様に、そのクラスがどういう役割を果たすものかを示すアノテーションです。リポジトリのようにデータベースにアクセスするためのクラスには、この@Repositoryアノテーションを付けておきます。

6.4.3 application.properties(設定ファイル)

application.proerties は、アプリケーションで使用する各種の値をプロパティとして保管しておくためのファイルです。Spring Bootでは、Spring関連の設定情報などを用意しておくのに使われます。

ここでは、これまで利用してきたXAMPP上のデータベース(MariaDB)に接続するための設定情報を記述しています。

6.4.4 BookControllerクラス(コントローラークラス)

次は、リポジトリを利用する際のポイントをチェックしていきましょう。

■リポジトリの関連付け

最初に@Autowiredアノテーションを使って、BookRepository インスタンスをフィールドに関連付けています。この@Autowiredというアノテーションは、アプリケーションに用意されているBeanオブジェクト(Spring MVCによって自動的にインスタンスが作成され、アプリケーション内で利用可能になったもの)に関連付けを行ないます。これにより、BookRepositoryのインスタンスが自動的にbookinfoフィールドに設定されます。

あれ?BookRepositoryってインターフェースのはずでは」と思った方、その通りです。が、ちゃんとインスタンスが設定されます。Spring MVCによりインターフェースに必要な処理が組み込まれた無名クラスのインスタンスが作成され、それが設定されるようになっているのです。

■Beanが登録されるまでの流れ
Spring Frameworkでは、あらかじめクラスをBeanとして登録しておき、そのBeanをインスタンスフィールドに自動的に関連付ける(つまり、代入する)ことで利用できるようにする、という処理をよく行ないます。

① アプリケーション起動
② @Repositoryインターフェースが検索される
③ 更に自動的にその実装クラスが作成・インスタンス化され、Beanとして登録される
④ コントローラーなどのクラスが読み込まれる際、@Autowiredが指定されているフィールドに登録済みのBeanから同じクラスが検索され、自動的にそのフィールドにインスタンスが割り当てられる

このような仕組みでフィールドに必要なリポジトリのインスタンスが割り当てられ、使えるようになるのです。

したがって、私たちが行うべき作業は「@Repositoryを指定したインターフェースを用意すること」「@Autowiredを指定したフィールドを用意すること」だけです。具体的な処理の実装は一切不要なのです。

■findAllメソッド
ここでは、repositoryの「findAll」というメソッドを使っています。

BookRepositoryには、findAllなんてメソッドは定義されていませんでしたね。これは、継承元であるJpaRepositoryに用意されているメソッドです。これにより、エンティティがすべて自動的に取り出されたのです。

6.4.5 list.html(テンプレートファイル)

最後に、画面にデータを表示するテンプレートを見ていきましょう。

今までに学習したThymeleafの変数式を利用しています。特別なことは何もありませんが、復習も兼ねてポイントを押さえておきましょう。


まず、61行目の th:if=”${book_list.size() >= 1}” でコントローラーから渡された変数 book_list の要素数を判定しています。もし条件を満たす場合は、その中の表示処理が行われます。

次に62行目の th:each=”book : ${book_list}” で各要素を1つずつ取り出し、th:object=”${book}” 取り出したオブジェクトを選択した状態で繰り返し処理を行ないます。

あとはもう簡単ですね。th:text=”*{title}” のように選択されたオブジェクトが持つフィールド変数を表示します。


NEXT>> 6.5 簡易書籍登録アプリケーション作成(JPA版)