Skip to content
Playground

演習: サービスとリポジトリ

この章では、TaskRepository を Spring に組み立てさせ、業務ルールを TaskService にまとめます。T- はタスク管理アプリ tasks の問題です。

T-6 では TasksControllernew 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/tasks
    • spring.datasource.username=root
    • spring.datasource.password=root
  • TasksControllerTaskRepository をコンストラクターで受け取る

一覧の見た目は T-6 と同じです。変わるのは、生成を Spring が行う点と、接続情報の置き場所です。

ヒント

本文 Repository接続設定の集約 のとおりです。@Repository を付けたクラスは Spring が生成し、コンストラクターの引数 DataSource も Spring が渡します。接続情報を application.properties に書けば、exclude の行を消しても Failed to configure a DataSource は出ません(DataSource を自動構成できるため)。

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()TaskRepositoryfindAll() をそのまま返す
  • add(TaskForm form):次の順に処理する
    • タイトルが空なら IllegalArgumentException を投げる
    • 未完了タスクが 10 件以上なら IllegalStateException を投げる
    • new Task(form.getTitle(), false, form.getNotes())save する

最後に TasksController を変えます。

  • TaskService をコンストラクターで受け取る(TaskRepository の代わり)
  • /taskstaskService.findAll()Model に渡す
  • POST /taskstaskService.add(form) を呼び、redirect:/tasks で一覧へ戻す

これで、追加フォームから送ったタスクが保存され、一覧に増えます。タイトルを空のまま送ると、IllegalArgumentException がそのままエラー画面に出ます(利用者への分かりやすい表示は後の章で扱います)。完了の切り替えと削除は、後の CRUD の章で扱います。

ヒント

検証を TaskService に置く理由は、本文 ルールを Service に置く理由 のとおりです。例外は本文 ビジネスルールの実装 と同じく、引数が不正なら IllegalArgumentException、状態による拒否なら IllegalStateException を使い分けます。

新規タスクは未完了なので、save では completedfalse を渡します。countActive()SELECT COUNT(*) ... WHERE completed = false の結果を、rs.next() のあと rs.getInt(1) で取り出します。上限の動作は、10 を一時的に小さい値に変えると確かめやすくなります。