前回、Spring Frameworkを導入してみました。そして、Spring BootでWeb(Spring MVC)とThymeleafを実際に利用してみました。今回は、Spring DATA JPAという機能を使ってデータベースとのデータをやり取りしてみたいと思います。
データベースには、MySQLを使っていきたいと思いますのでインストールしてない人は、インストールしておきましょう。
・MySQLのダウンロード&インストールと初期設定方法 | サービス | プロエンジニア
・Windows 10 HomeにMySQL 5.7.18を単体でインストール
JPA(Java Persistence API)って?
そもそも、JPA(Java Persistence API)って何なのさ?となり、
JPAはJava Persistence APIの略です。永続化およびオブジェクトとリレーショナルのマッピング管理用のJava APIの仕様です。Java EE環境に限らず、Java SEでも利用可能です。
や、
JPAは、JSRで定義されているJava標準技術の1つ(JSR338: Java Persistence API 2.1)です。つまり、Java言語の世界では、データベース利用の標準技術ということですね。
Java Persistence APIは、永続的にオラクル社が提供するデータベースに膨大な量のデータを格納するためのクラスとメソッドのコレクションです。
ということらしく、データベースに関わってくるようです。
具体的には、データベースのテーブルのレコードとJavaのオブジェクト間の 相互変換を行います。それにより、アプリケーション開発者がJavaのオブジェクトにアクセスすると、 その結果データベースへの操作が行われます。
JPAのイメージ図(すみません、かなりあやふやです)
⇧ こちらのサイト様が詳しく仕組みを紹介しているので、JPAの仕組みについてはこちらのサイトを参考ください。
さらに具体的に、
Persistenceは、永続性とか持続性などという意味なので、オブジェクトをそのままの形で永続的に保管したり、取り出したりするためのAPIという意味です。
同じようなことは、ObjectInputStreamやObjectOutputStreamを使ってもできます。これらを使うと、オブジェクトをファイルに保管することができます。
しかし、JPAはファイルではなく、データベースに保管するところが大きな違いです。簡単なJava言語のメソッドだけで操作できるので、従来のように、JDBCやSQLを使う必要はありません。
JDBCドライバが必要ないということですかね?
・Spring Boot/第三回 Spring Bootでデータベース操作(JPA編) - なべ’s blog
⇧ 上記サイトによりますと、データベースの操作には、
2種類があり、JavaのORマッピングの仕様「JPA(Java Persistence API=Javaの永続化のAPI)」でデータベースを操作する場合、JDBCではないのでJDBCドライバは必要なさそうです。
と思ったけど、
によりますと、JDBC使ってるっぽい...すみません、このへんちょっと分らんです。
データベースの世界とオブジェクトの世界とは、水と油ほども違うので、両者のつじつま合わせをする技術(ORM: Object Relational Mapping)の理解も必要ですが、それも今では、簡単なアノテーションをソースコードに書き加えるだけでいいことになっているので、簡単です。
アノテーションをつけることで、ORM(Javaのオブジェクトとデータベースのテーブルの相互変換) を行ってくれるようです。
JPAは仕様であって、実際にはベンダーがJPAを実装していて、提供されているものをJPAプロバイダというようです。
JPAの実装は、HibernateのようなO/R Mapperを開発しているベンダーによって、参照実装として提供されている。 このように、O/R Mapperを開発しているベンダーによって実装された参照実装のことを、JPAプロバイダと呼ぶ。
JPAプロバイダとしては、
などがあるみたいです。Spring DATA JPAはデフォルトだと内部的にHibernateで実装されているみたいです。
・Spring Data JPAのJPA実装をHibernateからEclipseLinkに変更する
⇩ EclipseLink、Hibernateでできることが違うようです。
Spring DATA JPA
Spring用のJPAライブラリのようです。Springでデータベースと連携する際は、これを使ってといて~、みたいな感じですかね?
・Spring Data – すべてのデータストアに対応するAPI?
⇧ によると、Spring DATAの中の1つがSpring DATA JPAっぽい感じですかね。
Spring Frameworkでも、JPAを利用してデータベースアクセスを行う「Spring Data JPA」というライブラリが用意されています。これは「Spring Data」と呼ばれるデータベースアクセス関連ライブラリの一つです。
この他に、非SQLであるMongoDBを利用する「Spring Data MongoDB」や、Hadoop利用のための「Spring Data Hadoop」などといったものが用意されています。
Spring Data JPAは、一般的なSQLによるリレーショナルデータベース全般を利用するためのもので、Spring Dataの基本となるライブラリといっていいでしょう。
Spring BootでJPAを利用するには、「pom.xml」に、「spring-boot-starter-data-jpa」とMySQLを使う場合は「mysql-connector-java」を追加します。
・50分で分かるSpring Data JPA/spring-data-jpa-in-50min // Speaker Deck
⇧ Spring Bootでない場合は、「hibernate-entitymanager」というものも必要になってくるようです。
Eclipse(「STSプラグイン」の入った)を起動し、プロジェクトの中の「pom.xml」を開きます。下の方にあるタブで「依存関係」を選択。
「依存関係」の「追加...」をクリック。
「spring-boot-starter-data-jpa」を検索、選択し、「OK」。
同じ流れで、「mysql-connector-java」も検索、選択し「OK」。
「依存関係」に追加されたら「Ctrl + S」でファイルを保存します。
すみません、今回は、「lombok」というものも追加しておきます。これを追加すると、@Dataアノテーションにて、各フィールドのアクセッサ(getterやsetter)メソッドを、@NoArgsConstructorで引数無しコンストラクター、@AllArgsConstructorですべてのフィールドを引数としたコンストラクターをそれぞれ自動生成してくれるようになるそうです。
・Lombok - @Getter / @Setter - 覚えたら書く
lombok を使うには、まずlombok自体をインストールしておく必要があるようです。(「pom.xml」の依存関係だけではダメみたいです...このへんの説明が少なくハマりました。公式サイト見ないと駄目ですね...。)
・Spring Boot lombok | Professional Programmer
なので、まずは、
https://projectlombok.org/download にアクセスし、「Download 1.16.18」というリンクをクリック。(バージョンを選びたい場合は、「older version」のリンクをクリック。)
ダウンロードされた「lombok.jar」というファイルをクリックします。「lombok」のインストーラーが起動するので、「Install / Update」をクリックします。(「Quick Installer」でも良いのかもしれないですが、検証してないです。)
「Install successful」と表示されたら、「×」で閉じてOKです。
IDE(自分の場合だとEclipse)を再起動しろとあるので、Eclipseを再起動します。
Eclipseを再起動したら、 「pom.xml」を開いて、「依存関係」の「追加...」をクリック。
「org.projectlombok lombok」を追加します。
「>」をクリックすると、バージョンが選べるようになるので、インストールした「lombok」のバージョンに合わせます。「OK」をクリック。
そしたら、「Ctrl + S」で保存しましょう。
これで、「lombok」が使えるようになるはずです。
データベース接続設定
Spring DATA JPAでデータベース接続する場合、データベース接続の設定は、「src/main/resources/」にある「application.properties」ファイルに記載するか、「src/main/resources/」に「application.yml」を作成して記載するか選べるようです。
その前に、データベースとテーブルを作成しておきます。コマンドプロンプトを起動しMySQLにログインします。
mysql -u root -p
データベースを作成し、データベースを選択し、テーブル作成し、データを入れておきます。
CREATE DATABASE sample; USE sample; CREATE TABLE user( id int(11) NOT NULL auto_increment, name VARCHAR(20), PRIMARY KEY(id) ); INSERT INTO user (name) VALUES('ユーザー名'); SELECT * FROM user;
それでは、データベースの接続設定を記述します。今回は、デフォルトで用意されている「application.properties」ファイルに記載していきます。
「username」「password」は各自の設定に合わせてください。今回はrootユーザーを利用してますが、他のユーザーを使う場合は、データベースに対して、権限の設定が必要です。
・権限の設定(GRANT文) - ユーザーの作成 - MySQLの使い方
spring.datasource.url=jdbc:mysql://localhost:3306/sample spring.datasource.username=root spring.datasource.password=root spring.datasource.driverClassName=com.mysql.jdbc.Driver #SQLのログの出力 logging.level.org.hibernate.SQL=debug logging.lovel.org.hibernate.type.description.sql.BasicBinder=\trace #SQLログを読みやすくする spring.jpa.propaties.hibernate.format_sql=true
・50分で分かるSpring Data JPA/spring-data-jpa-in-50min // Speaker Deck
⇧ 参考にさせていただいたんですが、今回、特にhibernateを入れた覚えがないのでもしかしたら、SQLのログ出力のところは機能しないかもです。
設定できましたら、
- Entityクラス
- Repositoryインターフェイス
- Serviceクラス
- Controllerクラス
を作成していきます。まずは、それぞれのフォルダ(パッケージ)を作成。
「パッケージ・エクスプローラー」の「src/main/java」直下のパッケージを選択した状態で、「新規(W)」>「フォルダー」を選択。
「フォルダー名(N)」を入力し、「完了(F)」。
同じ流れで、それぞれフォルダを作成します。(フォルダ名は分かりやすければ大丈夫かと。)
まずは、「repository」インターフェイスから作成。「新規(W)」>「インターフェイス」を選択。
「名前(M):」を入力し、「拡張インターフェイス(I)」の「追加(A)...」をクリック。
「JpaRepository」を検索し、選択し「OK」をクリック。
「拡張インターフェイス(I)」が追加されたら「完了(F)」。
ファイルにエラーは出ますが、後で編集していきます。
次に、「Entity」クラスを作成。「新規(W)」>「クラス」を選択。
「名前(M):」を入力し、「インターフェイス(I):」の「追加(A)...」をクリック。
「Serializable」を検索、選択し「OK」。
「インターフェイス(I):」が追加できたら「完了(F)」をクリック。
次に「Service」クラスを作成。「新規(W)」>「クラス」を選択。
「名前(M):」を入力し、「完了(F)」をクリック。
最後に、「Controller」クラスを作成。
「名前(M):」を入力し、「完了(F)」。
表示用のhtmlファイルも作成しておきます。「src/main/resource」の「新規(W)」>「その他(O)...」を選択。
「Web」>「HTMLファイル」を選択し、「次へ(N)>」をクリック。
「ファイル名(M):」を入力し、「次へ(N)>」をクリック。
「完了(F)」をクリック。
htmlファイルができました。
ファイルの編集
Entityクラス(User.java)
クラスに@Entityと、フィールドに 主キーは必須のようで主キーには@Idをつける必要があるようです。(主キーないテーブルとかどうすればいいんでしょうね?)
・MySQLで主キー制約を設定する「PRIMARY KEY」 | UX MILK
⇧ 主キーは、MySQL だとPRIMARY KEYのついてるものらしいです。
⇩ 他のEntityに対するアノテーションは下記サイトへ
・JPA関連アノテーションの基本として-その1- - A Memorandum
・@GeneratedValueを使って主キーを生成する方法 - Qiita
package com.example.demo.Entity; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Entity @Data @NoArgsConstructor @AllArgsConstructor public class User implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(nullable = false) private Integer id; private String name; }
Repositoryクラス(UserRepository.java)
基本的には、JpaRepositoryインターフェイスを継承しておけば問題ない?ようですかね。
・JpaRepository と CrudRepository の違いって何? - Qiita
JpaRepositoryインターフェイスを継承したインターフェイスを作成すると、基本的なCRUD処理(SELECT、INSERT、UPDATE、DELETEなど)が自動生成されるようです。@Repositoryは必要ないみたいです。
・50分で分かるSpring Data JPA/spring-data-jpa-in-50min // Speaker Deck
package com.example.demo.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.example.demo.Entity.User; public interface UserRepository extends JpaRepository<User, Integer> { }
Serviceクラス(UserService.java)
Repositoryインターフェイスを利用して、実際のSQLの処理を行っていくのがServiceクラスの役目らしいです。(イメージ的にはDAOクラスみたいな感じですかね?)
@Autowiredアノテーションをつけることで、newしなくても利用できます。これによってUserRepositoryはインターフェイスであるので、本来ならクラスに継承させインスタンス化させることが必要ですが、そうしたことをしなくてもUserRepositoryのメソッドが利用できるようです。
DI(Dependecy Injection)、日本語でいうところの「依存性の注入」を、@Autowiredアノテーションで実現してるようです。
package com.example.demo.Service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.demo.Entity.User; import com.example.demo.repository.UserRepository; @Service public class UserService { @Autowired UserRepository repository; public User search(Integer id) { User user = repository.findOne(id); return user; } }
Controllerクラス(UserController.java)
@Controllerをつけることで、View側のhtmlファイルを返してくれるようになります。
・Spring Boot解説第18回(基本編:Controllerとは) - Qiita
⇧ によりますと、他にも@RestControllerというものがあり、こちらはJSON や XML などを返すときに利用していくようです。
@RequestMappingで遷移先を指定してます。(「http://localhost:8080/user」でアクセスされたときに、ここのクラスに処理がやってくる感じです。)
@Autowiredは、Serviceのところでも使われていたのですが、クラスにも使えるようです。
@RequestMapping(method=RequestMethod.GET)でGETの場合、@RequestMapping(method=RequestMethod.POST)でPOSTの場合というように処理を分けれるようです。
・【Spring MVC】@RequestMapping の基本 - 山崎屋の技術メモ
ModevAndViewを使用するとViewに渡したい情報を一緒に返すことができる。
package com.example.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import com.example.demo.Entity.User; import com.example.demo.Service.UserService; @Controller @RequestMapping("/user") public class UserController { private static final String VIEW = "user"; @Autowired public UserService service; @RequestMapping(method = RequestMethod.GET) public String index() { return VIEW; } @RequestMapping(method = RequestMethod.POST) public ModelAndView userList(ModelAndView mov, @RequestParam("userId") String userId) { mov.setViewName(VIEW); User user = service.search(Integer.parseInt(userId)); mov.addObject("user", user); return mov; } }
View側(user.html)
Thymeleaf はxmlとして扱われる?ようなので、必ず閉じが必要になります。<form></form>のように閉じタグがあるものは良いのですが、<meta charset="UTF-8">のような閉じタグがないものは、<meta charset="UTF-8" />のように末尾に「/」を加えないと実効後、エラーが出ます。
<input>タグも同じように末尾に「/」を入れるように注意しましょう。
「lombok」を使うと「${user.id}」のようにして「フィールド」の値が取得できるようです。
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>SPRING DATA JPA</title> </head> <body> <form method="POST" name="form"> ユーザーID: <input type="text" name="userId" value="" /> <input type="submit" value="検索" /> </form> <div th:if="${user != null}"> <p th:text="${user.id}"></p> <p th:text="${user.name}"></p> </div> </body> </html>
Entityクラス(User.java)を開いて、「ビュー」の「アウトライン」見ると、アノテーションによって、アクセッサ(getterやsetter)メソッドとコンストラクターが存在しているのが分かります。 (「アウトライン」はEclipse上部の「ウィンドウ(W)」>「ビューの表示(V)」>「アウトライン」から開けます。)
実際にサーバーで実行してみます。プロジェクトを選択した状態で右クリックし、「実行(R)」>「Spring Boot アプリケーション」を選択。(2回目からは普通の実行ボタンのほうでもいけます。)
「http://localhost:8080/user」にアクセス。
userテーブルに登録されているidが1なので、1を入力すると、
データベースのデータが取得でき、無事表示できました。
⇩ 高度なSpring Data JPAの利用については下記サイトへ
・Spring Data JPAのEntityの相互参照とその注意点 - Qiita
Springの仕組みをいろいろ覚えていかねばですね...覚えること多すぎますね(涙)