SpringBoot JPARepository 使ってみた

未分類

DBとの接続はWebアプリでは避けて通れないわけですが、

あまりよくわからないまま、JDBC、mybatisあたりを使っていたので今回は、DBの操作を行うJPAってのを使ってみたいと思います。

JPAとは!

Java Persistance APIの略で、

RDBのデータを扱うJavaEEアプリを開発するためのフレームワーク。。

らしいです!笑

Java Persistence API - Wikipedia

O/R MappingやDAOの技術仕様らしく、それを実装したものが

・EclipseLink

・Hibernate ORM

・Apache Open JPA

みたい。

この人のがわかりやすかったです。

JPAの基礎1 - Qiita
# JPAの概要 ### JPAとは? JPAは「(」の略称であり、**Java EE標準のO/R Ma...

Hibernateってよく聞くけど、これはJPA仕様を実装したO/R Mapperやったんですね!勉強になります!

ところで、O/R Mappingとはって話ですが、これは私なりにかいつまんで説明すると、Object / Relational Mappingの略で、JavaでいうオブジェクトとRDBでいうテーブルを紐付けましょう!って思想。

あとで紹介するソース見てもらったら早いんですが、Javaのクラス自身のフィールドにRDBのテーブルのカラムを持ってます。で、データをセレクトすると勝手にインスタンスが生成されて(もちろんフィールドには、取得したカラムの値がばっちし入ってます)取得できるって感じ。

めちゃくちゃすげーやん!!

でね。こいつを使いやすくするための機能をSpringBootは持ってはるんすわ!

やるね!

では、実際に作ってみよう!

今回は、DBを別途用意するんめんどかったんでJavaライブラリとして利用できるH2を使ってデータ永続化操作をやっていきたいと思います!

ちなみに、ビルドツールにはMavenを使ってやりますんで、Gradle使ってる人は読み替えてください。

では早速、やってきますか!

手順は以下の通りです

1:dependencyの追加

2:RDBのテーブルに当たるJavaクラス(Entityクラス)を作成

3:リポジトリを作成する

4:リポジトリを利用する

5:テンプレートを作成する

1:dependencyの追加

pom.xmlに次のdependencyを追加していきます

「JPA」「Thymeleaf」「Web」「H2」

2:RDBのテーブルに当たるJavaクラス(Entityクラス)を作成

ざっと、長くなってますが、Getter/Setterのせいです。笑

Lombok使うと省略できるみたいやけど、今回はなしで!

クラスに@Entityっていうアノテーションをつけます。

その下に@Tableアノテーションありますが、もしクラス名がテーブル名と一致する場合、つけなくても良いらしい。今回は違うのでつけてます。

@Idアノテーションは主キーをさします。

その下にある@GeneratedValueってのは、主キーのフィールドに対して値を自動生成するためのアノテーションです。

strategy=GenerationType.AUTOとすることで、自動で値を割り振ってくれます。

@Columnアノテーションは、フィールド名がカラム名と一緒の場合は、省略できます。

そのほかの@NotNullや、@NotEmptyなんかは、あとで出てくるバリデーションチェックの時に詳しく説明します。それぞれnullであったり、空はダメって感じの意味のアノテーションです。

3:リポジトリを作成する

こいつは、データベースアクセスのための基本的な、ほんまに基本的な手段を提供してくれるものです。

より高度なデータベースアクセスの手段を提供してくれるEntityManagerっていうのもあるみたいやけど、そいつは今回ノータッチで。

このリポジトリですが、データベースアクセスの処理(汎用的なCRUDですね)を自動的に生成し、実装してくれます。

なので、コードはほとんど書きません笑

ではでは、リポジトリとはどんなもんかみてみましょう。

はい、これだけー

注目すべきは、JpaRepositoryインターフェースを継承しているところです。

ジェネリックスにMyDataクラスとLongクラスを指定しています。

MyDataクラスを紐付けまっせーってことと、主キーの型はLongでっせーてこと。

@Repositoryアノテーションは、stereotypeのアノテーションの1つで、このクラスがデータベースアクセスのクラスですよーって明示しているだけです。

※他のstereotypeのアノテーションには、@Controllerや、@Service、@Componentなんかがあって、それぞれ「リクエストハンドラー」「業務ロジック」「それ以外(データベースアクセスでもない)」って感じです。

なんで、別に@Controllerアノテーションをつけても構わないとは思います笑

ソース見た時に気持ち悪すぎますが。。。

っでこのfindByIdってメソッドが、引数にもらったIdで検索しまっせ!ってこと。

あ、これはフィルタリング条件にしたいカラムがNameだったら、findByNameってすりゃいいし、IdとNameとかだったら、findByIdAndNameってやればいいです。

ちなみに、こういったテーブルのカラムによってメソッド名が変わるものについては、このRepositryインターフェースにメソッドを定義(実処理はいらない)しないといけませんが、findAll(全件検索)とかだと、実装すりゃしなくていい。なので、このリポジトリ使ってfindAllメソッドを呼ぶことができる。

あとで見せますねー

4:リポジトリを利用する

では、作成したリポジトリインターフェースを使ってみよう!

リクエストハンドラークラスから直接使っちゃおうと思います。

※商用では、ちゃんとビジネスロジック側で使ってください。

はい、おなかいっぱいです。。。

上から咀嚼していきたいと思います。

まず、stereotypeのアノテーション@Controllerはいいですね。

このクラスはリクエストハンドラーです。

次の@Autowiredで作成したMyDataRepositoryをDIしています。

ここで、疑問が出ますね。MyDataRepositoryってインターフェースちゃうん?!っと。

Springフレームワークのすごいとこなんやね。これが。

SpringMVCによって、インターフェースに必要な処理が組み込まれた無名クラスのインスタンスが作成され、それが設定されてるんです!すごない?!

次の@PostConstructですが、こいつはサブ要素なんでほぼスルーでもいいです。

何かと言うと、このアノテーションがついているメソッドは、コンストラクタによってインスタンスが生成された後に呼び出されるってことを意味していて

@Controllerアノテーションをデフォルトスコープで実装しているこのMainControllerクラスは、シングルトンなので起動時に一度だけインスタンスが生成されます。したがってそのインスタンス生成時に一度だけ呼ばれるメソッドということになります。そのメソッド内でデータを作ってあらかじめDBに入れてるってだけです。

このsaveAndFlushメソッドが引数に渡したEntityクラスをDBに登録するメソッドです。

次、@RequestMappingアノテーションですが、こいつはvalueに設定しているパスに、methodに設定しているHTTPメソッドでリクエストがきた場合に、処理をさせるようにURLマッピングをさせるものです。

で、indexメソッドの引数にある@ModelAttributeですが、こいつは画面側を作る際に説明します。

あ、ちなみにThymeleafの使い方とかそこへの値の渡し方とかは、本記事の守備範囲外なので、知らない人は調べておいてください。

はい、ではindexメソッドの中身です。

出ました!findAllメソッド!

DIしたMyDataRepositoryのfindAllメソッドを呼んでDB内のデータを全て取得してきてます。

取得したものは複数件存在するため、Iterable型です。

最後に取得したデータをdatalistというキー名でテンプレート側に渡して終わり。

2つ目のformメソッドは、POSTされた時に呼ばれます。

引数の@ModelAttributeはテンプレート側作成時に説明するので割愛。

@Validatedですが、これは、@Entityを作成した時を思い出してください。

そう!@NotNullや、@NotEmptyってありましたよね。これらのアノテーションがついたフィールドがnullであったり空かをチェックしてくれるアノテーションが@Validatedです!

で、このチェック結果が次の引数BindingResultに格納されます。

なので、formメソッドの中身は、最初のBindingResult結果のチェックから始まります。

result.hasErrors()で1つでもエラーがあればtrue が返ってきます(複数バリデーションチェック用のアノテーションが存在するため)

エラーがなかったら、データをDBに登録して、あった場合は再度DBからデータを全件取得してindex.htmlを表示します。

最後に、重要なアノテーションの説明。

@Transactionalです。DBにデータを格納するためreadOnly=falseとしてトランザクションを張ってます。データ更新が入る部分はトランザクション忘れずに!

5:テンプレートを作成する

では、ラストにテンプレートを作成して動かしてみましょう!

注目すべきはformタグの「th:object=”${formModel}”」です!

このformModelって文字列、どこかで見たことありますよね。

そうです。MainControllerのメソッドの引数にあった「@ModelAttribute(“formModel”) MyData myData」の部分です!

このアノテーションで指定したformModelをテンプレート側で「th:object」で指定することで、MyDataクラスのフィールド変数の値を参照することができるっていうカラクリです。ちなみに、フィールド変数を参照するときは「*{フィールド変数名}」となります。

GETアクセス時は、MyDataの引数にはnewされたインスタンスが作成されて割り当てられるので、値は何も入っていません。

しかし、POSTアクセス時のMyDataには、送信されたフォームの値が自動的にMyDataインスタンスの変数に格納されて引数として渡される。

パラメータをいちいち個別に取得しなくていいし、バリデーションチェックもアノテーションでできるし、めちゃ便利ですよね!!

あと、th:errorclassってのは、バリデーションチェックでエラー判定になった場合に、ここで指定したものがclass属性の値としてHTMLタグを作成するものです。

で、th:if=”${#fields.hasErrors(‘name’)}”ってのが、th:objectで取得したMyDataクラスのフィールドのnameって変数がバリデーションチェックでエラーとなっているかの条件分岐です。エラーになっている場合、このdivタグは表示されます。

以上でざっとコードの説明は終わりです。

では、早速動かしてみましょう!

私は、VSCodeでSpringBootプロジェクトを作成しているので、

./mvnw clean packageコマンドでビルドして、target内のjarファイルを

java -jar で実行します。

初期画面はこんな感じです。

ライン下側が、@PostConstructで初期登録したデータです。

普通に登録してみましょう!

はい!無事に登録できてます!

では、次にあえてバリデーションで引っかかってみましょう!

これなんで、nameの部分を空白にして、ageの部分を201以上にしてみます。

無事に引っかかりました!笑

ちなみに、このエラーメッセージの文言ですがこれも自分で決めれます。

やり方は、resourcesフォルダ内に「ValidationMessages.properties」というファイルを作成します。中身はこんな感じです。

はい、なんじゃこりゃ!ですね笑

ていうのもこの辺のファイルを日本語で書いてしまうと文字化けしてしまうので、ascii変換しないといけないんです。

変換コマンドはこんな感じ

ちなみに変換前 がこれ

今回の場合は、日本語が書いてあるファイル名と変換後のファイル名は同じValidationMessages.propertiesになります。

で、中身の説明は、するまでもないですね。各アノテーションで引っかかった場合に出力するmessageに日本語を入力しているだけです。

駆け足で説明してきたけど、個人的には、SQLとJavaのオブジェクトを紐付けるmybatisの方が好きです。自分でSQL文を書けるし、推論はできるけど別途、JPAのメソッド覚えるのしんどかった笑

しかも、JPAやとSQLは勝手に生成されてまうから(自分でSQLを書く方法もあるみたい。。でも、それやったらJPA使うメリットなくね?)、JOINとかしたかったらI/Oが多くなりそうやし。。

あ、でも私みたいなんは、そこまでSQL詳しくないから、大人しくJPA使っとくのもありか。。笑

ってことで、次回はmybatisについて書いてみたいと思いまーす

BYE

コメント

タイトルとURLをコピーしました