概要 / 説明
Kotlinでサーバーサイドアプリケーションを作ってきましたが、まだきちんとした構成にはなっていない状態です。
「ことりんと一緒 Springもね - 2. RestController と Data Class」 でコントローラクラスを作り、直接データを扱うような構成のままです。
そこで、少しずつ変更を行っていきます。
まず、ここでは「サービス」層を考えていきます。
Webアプリケーションでは大きく分けて次のような機能が必要となります。
- リクエスト/レスポンスの処理
- アプリケーションロジックの処理
- データの処理
今まではこれらの機能を単一レイヤで担当していました。
このままの構成だと、扱うロジックが増え、データモデルが複雑になってくると、
1つのクラスが巨大になり開発/保守効率が悪くなってしまいます。
それぞれの機能を分離して、複数のレイヤに分けていきます。
さて、作っていたクラスが RestController
ということで、
本来はリクエスト/レスポンスを扱うことを責務とします。
そこで、それ以外の処理を切り出し、それを サービス とします。
前提 / 環境
ランタイムバージョン
- Kotlin : 1.3.0
- SpringBoot : 2.1.0.RELEASE
Spring Dependencies
- Web
- Actuator
開発環境
- OS : Mac
- IDE : IntelliJ IDEA
- Build : Gradle
手順 / 解説
変更前のコントローラクラス
元々は以下のようにコントローラクラスの中でデータの生成など、リクエスト/レスポンスの処理以外のことを行っていました。
@RestController
@RequestMapping("/messages")
class SimpleController {
@GetMapping
fun getMessages() : List<Message> {
return listOf(
Message(
UUID.randomUUID().toString(),
"First Message",
"This is a 1st message on ${getDate()}."
),
Message(UUID.randomUUID().toString(),
"Second Message",
"This is a 2nd message on ${getDate()}."
)
)
}
private fun getDate() : String {
val simpleDateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
return simpleDateFormat.format(Date())
}
}
サービスクラス
元々コントローラクラスに実装していた内容を以下のようにサービスクラスに移します。
@Service("Message Service")
class MessageService {
fun getMessages() : List<Message> {
return listOf(
Message(
UUID.randomUUID().toString(),
"First Message",
"This is a 1st message on ${getDate()}."
),
Message(UUID.randomUUID().toString(),
"Second Message",
"This is a 2nd message on ${getDate()}."
)
)
}
private fun getDate() : String {
val simpleDateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
return simpleDateFormat.format(Date())
}
}
サービスクラスには @Service
アノテーションを付与します。
これによりコントローラクラスの中で Dependency Injection により利用できるようになります。
@Autowired
private lateinit var service: MessageService
lateinit
キーワードは、インスタンスを初期化せずに宣言するときに使用します。
変更後のコントローラクラス
サービスクラスを使用するコントローラクラスでは、リクエスト/レスポンスに関する処理だけを担当するようにします。
以下のようにサービスクラスで実装している処理を呼び出すように変更を行います。
@RestController
@RequestMapping("/messages")
class MessageController() {
@Autowired
private lateinit var service: MessageService
@GetMapping
fun getMessages() = service.getMessages()
}
まとめ / 振り返り
責務ごとにレイヤを分けてアプリケーションを開発するのことは、今や定石ですね。
まだ、この状態ではサービスレイヤからデータ処理を直接行うようになっているので、
次はその部分を分離していきます。