目標
複数回に分けて実施予定です。
また、以降の記事ではエスケープのため、各項目の@を全角にしています。(コード内は半角なのでご安心ください)
(今まで@
とすることでエスケープさせていましたが、見づらい気がしたので...)
- SpringBootとは何かをざっくり知る
- 環境構築&Hello World!を表示させる
- パラメータやオブジェクトの受け渡しをする
- 他の機能にも触れてみる ←今回やること
他の機能・・・ちょっとフワっとしてますね。改めて具体的に書きます。
目標(他の機能について)
- DBを操作してみよう(JPA編) ←今回やること
- DBを操作してみよう(MySQL編)
- バリデーション(入力チェック)を導入しよう
- プロパティファイルを読み込もう
- actuatorに触れてみよう(おまけ)
- 自作のタグプレフィックスを作ろう(おまけ)
DBを操作してみよう(JPA編)
プロジェクトは前回のものを使いまわします。
作り直してもいいのですが、プロジェクトの作成後にmavenの依存関係を追加する
という工程を入れたいと思ったためです。
依存関係の追加
今回はDB操作ということでH2databaseとSpring Data JPAを追加します。
-
H2database
javaのメモリ上で展開することのできるデータベースです。これによりSQL Server
やMySQL
といったソフトウェアを用意することなく、サクッとデータベースの機能を使うことができます。 -
Spring Data JPA
javaでO/Rマッピング
を行うための機能です。ただ、JPA(Java Persistence API)
はこの機能の概念であり、実装はHibernate
と呼ばれるライブラリが担っています。O/Rマッピングって?
正式名称はObject-Relational Mapping
で、プログラミング言語とデータベースを繋ぐ仕組みのことです。これを利用することで、直感的に書いたソースコードでSQLの操作が可能になります。javaの場合だとJPA
のほかにMybatis
等のフレームワークがあります。
依存関係を後から追加する方法を幾つか紹介します。
1以外は見なくても特に影響ありません。
終わり!これが一番手っ取り早いかもしれませんね。
1.pom.xmlにコピペ
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
こういったテンプレートコードはググったり、Mavenのセントラルリポジトリから持ってきます。
・Maven リポジトリ検索
しれっと出てきた<scope>って何?
依存関係を追加するタイミングを指定するオプションになります。
自分もruntime
とtest
ぐらいしか知らないので、全て載っているサイトを引用させてもらいます。
名称
機能
compile
scope の指定を省略した場合のデフォルト値です。全ての状況でクラスパスに追加されます。
provided
ライブラリが JDK やコンテナによって提供される場合に指定します。コンパイル時のみクラスパスに追加されます。
runtime
実行時のみに必要な場合に指定します。テストの実行および通常の実行のときにクラスパスに追加されます。
test
テストのときのみ必要な場合に指定します。テストのコンパイルと実行のときにクラスパスに追加されます。
system
明示的にクラスパスに追加する場合に指定します。このスコープのライブラリは常に有効であるとみなされ、リポジトリの検索は行われません。
グループId=
2.Mavenの機能で追加
右クリック>Maven>依存関係の追加
の順にクリック。
com.h2database
アーティファクトId=h2
スコープ=runtime
※
を指定してOKをクリック。
※ スコープって何?については1.pom.xmlにコピペを参照してください。
もう一回この画面を開いて
グループId=org.springframework.boot
アーティファクトId=spring-boot-starter-data-jpa
スコープ=compile
(おそらくデフォルトで選択済み)
を指定してOKをクリック。
終わり!ぶっちゃけ<dependency>
とかのタグを自動で記述してくれるぐらいのメリットしかありません。
プロジェクト上、もしくはpom.xml上で 原因は色々あるので特定するのは難しいです。
3.Mavenの機能で追加(検索利用)
右クリック>Maven>依存関係の追加
の順にクリック。
グループID、アーティファクトID、または・・・にh2d
を入力
検索結果に表示されたcom.h2database
を選択※1
スコープはruntime
を選択※2
最後にOKをクリックすると追加されます。
※1 何も表示されない場合はこちら
※2 スコープって何?については1.pom.xmlにコピペを参照してください。
もう一度画面を開いて、
グループID、アーティファクトID、または・・・にdata-jpa
を入力
検索結果に表示されたspring-boot-data-jpa
を選択
スコープはcomplie
のまま(デフォルトで選択状態のはず)
最後にOKをクリックすると追加されます。
終わり!
2.Mavenの機能で追加にないメリットとしてはアーティファクトIDをフルで覚える必要がない
ぐらいです。
また、出来た方は下の何も表示されない場合
は飛ばしてください。
何も表示されない場合
検索欄に3文字以上入力しないと表示されない
のは仕様っぽいですが、以下の画像のようにインデックスのダウンロードが・・・
と出ているとたまに機能しなくなります。この場合、今から説明する方法で半数の人は直るかと思います。
ウィンドウ>設定>Maven
の順にクリック。
起動時にリポジトリー・インデックス更新をダウンロード
をチェックして適用して閉じる
をクリック。
ファイル>再開
の順にクリックしてSTSを再起動します(普通に×閉じ再起動でも大丈夫です)。そのあと、STSの右下にインデックスの更新中
が表示されていればOKです。(完了には数分~数十分かかります)
これが完了すると検索できるようになるかもしれません。
pom.xmlに追加した依存関係がプロジェクトに取り込めていない時もあるのでプロジェクトを更新します。Maven>プロジェクトの更新
の順にクリック。
プロジェクトdemo
にチェックし、OKをクリック。
更新完了です!
テーブル用クラスの作成
依存関係の追加が終わったら、まず初めにテーブル用クラスを作成しましょう。
com.example.demo
内にUserEntity
を作成し、以下のコードを書きます。
package com.example.demo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="user")
public class UserEntity {
@Id
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
アノテーション祭りですね。順に解説します。
-
@Entity
記述したクラスをエンティティクラス(DBの機能を持ったクラス)として認識させます。 -
@Table
name
: テーブル名を設定します。 -
@Id
記述したプロパティを主キー(レコードを一意に特定するためのカラム)として認識させます。 -
@Column
記述したプロパティをカラムとして認識させます。
name
: カラム名を設定します。
length
: カラム長を設定します。
nullable
: NULLを許容するか設定します。
@Column(name="name",length=10,nullable=false)
private String name;
-
@GeneratedValue
strategy
: 主キーの採番方法を指定します。GenerationType.AUTO
の場合、利用するDBに合わせて最適な自動採番(オブジェクトが生成されるごとに1,2,3...と増えていく)が行われるようになります。
リポジトリの作成
続いてUserRepository
という名前でインターフェースを作成し、以下のコードを追加してください。
package com.example.demo;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<UserEntity, Long> {
public UserEntity findById(int id);
}
-
JpaRepository
依存関係の追加で触れたJPAの機能を使うために記述します。総称型となっており、<使用するエンティティクラス, Long>
を指定します。 -
JpaRepository#findById
SQL文の代わりを果たすメソッドになります。本来インターフェースは実装(継承した具象クラスを作ること)しなければ意味がありません
が、このように命名規則に従ってメソッド名や引数を定義してあげると、JpaRepositoryがそれに応じた機能を自動で作成
してくれます。
他にも沢山の命名規則があるので、気になった方は公式ドキュメントも読んでみてください。
・Spring公式ドキュメント 6.3.2.クエリ作成
コントローラの作成
既に作成してあるDemoController.java
を以下のように書き換えます。
package com.example.demo;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
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;
@Controller
public class DemoController {
@Autowired
private UserRepository repository;
@PostConstruct
@Transactional
public void init() {
UserEntity entity = new UserEntity();
entity.setName("hatopo");
repository.saveAndFlush(entity);
}
// このメソッドは特に変更なし
@RequestMapping(value="/",method=RequestMethod.GET)
public ModelAndView index() {
ModelAndView mav=new ModelAndView();
mav.setViewName("/index");
return mav;
}
@GetMapping("/hello")
public ModelAndView hello(@RequestParam int id,ModelAndView mav) {
UserEntity entity = repository.findById(id);
mav.addObject("name",entity.getName());
mav.setViewName("/hello");
return mav;
}
}
-
@Autowired
これをオブジェクトに付けると、Springが自動でオブジェクトの生成をしてくれるようになります。DI(依存性注入)を行ってくれる
とも言います。DI(依存性注入)とは?
一言でいうと依存性を注入すること
です。
依存・・・Aクラスが内部でBクラスを利用している時、AはBに依存している
といいます。
注入・・・外部から与える
という意味です。 すなわち、クラス内で利用する予定の別クラスを外部から渡してあげること
です。 -
@PostConstruct
これを付けたメソッドは、SpringBootの起動直後に一度だけ呼び出されるようになります。 -
@PreDestroy(今回は使用しません)
PostConstructと対になっているので紹介。こちらはSpringBootの終了直前に一度だけ呼び出されるようになります。 -
@Transactional
これを付けたメソッドもしくはクラスは、トランザクション処理(エラーが発生したら巻き戻せる機能)を行えるようになります。
readOnly
: DBを読み取り専用にするか指定します。デフォルトはfalseです。
timeout
: タイムアウトの時間を秒数指定できます。
rollbackFor
: デフォルトの巻き戻し対象であるRuntimeExceptionやSQLException以外のエラーも対象にしたい場合に記述します。
@Transactional(readOnly=true,timeout=100,rollbackFor=IllegalArgumentException.class)
-
@JpaRepository#saveAndFlush
引数のオブジェクトをメモリ上のDBに反映させます。
ビューの作成
index.html
とhello.html
の<body>内も書き換えます。
<body>
<form action="/hello" method="get">
IDを入力してください<input type="text" name="id"><br>
<input type="submit" value="送信">
</form>
</body>
<body>
<span th:text="${name}"></span>さん、おはようございます!
</body>
実行
それではhttp://localhost:8080
にアクセスします。
入力欄に1
を入れて次へ進むと・・・
メモリ上に展開したDBからid検索を行い、一致したレコードのname(hatopo
)を表示することができました!
今回、特に入力チェックなどは書いていないため、文字列を入れたり存在しないIDを入れたりするとエラーになるのでご了承ください。
おさらい
- H2databaseを使ってメモリ上でDBを展開
- JPAを使ってjavaのコードでSQLを操作
- @Entity、@Tableでエンティティの定義
- @Id、@Column、@GeneratedValeでカラムの定義
次回はMySQLを操作していきましょう。お疲れさまでした。