演習: サービスとリポジトリ
この章では、TaskRepository を Spring に組み立てさせ、業務ルールを TaskService にまとめます。T- はタスク管理アプリ tasks の問題です。
T-7. TaskRepository の DI
Section titled “T-7. TaskRepository の DI”T-6 では TasksController が new TaskRepository() で生成し、接続情報を TaskRepository に直接書いていました。本文 Repository と同じく、生成と注入を Spring に任せ、接続情報を application.properties にまとめます。次のとおり変えます。
TaskRepositoryに@Repositoryを付ける- 接続は
DataSourceをコンストラクターで受け取り、dataSource.getConnection()で得る application.propertiesに接続情報を書き、spring.autoconfigure.excludeの行を削除するspring.datasource.url=jdbc:mysql://127.0.0.1:3307/tasksspring.datasource.username=rootspring.datasource.password=root
TasksControllerはTaskRepositoryをコンストラクターで受け取る
一覧の見た目は T-6 と同じです。変わるのは、生成を Spring が行う点と、接続情報の置き場所です。
ヒント
本文 Repository と 接続設定の集約 のとおりです。@Repository を付けたクラスは Spring が生成し、コンストラクターの引数 DataSource も Spring が渡します。接続情報を application.properties に書けば、exclude の行を消しても Failed to configure a DataSource は出ません(DataSource を自動構成できるため)。
T-8. TaskService と保存
Section titled “T-8. TaskService と保存”T-4 で作った POST /tasks は、まだタスクを保存していません。本文 Service と同じく、業務ルールを持つ TaskService を作り、保存を実装します。
まず TaskRepository に 2 つのメソッドを次のとおり実装します。
save(Task task):INSERT INTO tasks (title, completed, notes) VALUES (?, ?, ?)でタスクを 1 件追加するcountActive():SELECT COUNT(*) FROM tasks WHERE completed = falseで未完了タスクの件数を返す
次に TaskService を @Service として定義します。
findAll():TaskRepositoryのfindAll()をそのまま返すadd(TaskForm form):次の順に処理する- タイトルが空なら
IllegalArgumentExceptionを投げる - 未完了タスクが 10 件以上なら
IllegalStateExceptionを投げる new Task(form.getTitle(), false, form.getNotes())をsaveする
- タイトルが空なら
最後に TasksController を変えます。
TaskServiceをコンストラクターで受け取る(TaskRepositoryの代わり)/tasksはtaskService.findAll()をModelに渡すPOST /tasksはtaskService.add(form)を呼び、redirect:/tasksで一覧へ戻す
これで、追加フォームから送ったタスクが保存され、一覧に増えます。タイトルを空のまま送ると、IllegalArgumentException がそのままエラー画面に出ます(利用者への分かりやすい表示は後の章で扱います)。完了の切り替えと削除は、後の CRUD の章で扱います。
ヒント
検証を TaskService に置く理由は、本文 ルールを Service に置く理由 のとおりです。例外は本文 ビジネスルールの実装 と同じく、引数が不正なら IllegalArgumentException、状態による拒否なら IllegalStateException を使い分けます。
新規タスクは未完了なので、save では completed に false を渡します。countActive() は SELECT COUNT(*) ... WHERE completed = false の結果を、rs.next() のあと rs.getInt(1) で取り出します。上限の動作は、10 を一時的に小さい値に変えると確かめやすくなります。