サンプルコード、githubにあげてます
https://github.com/maeharin/kotlin-dvd-rental
● Kotlin x Spring Boot x Doma2で作ったAPIサーバーのサンプル
● DBにPostgreSQL、検索にElasticsearch(Dockerで起動)
● Postgresql tutorialのDVD Rentalサンプルデータベースを利用
controller
@RestController
@RequestMapping("/api/v1/films")
class FilmRestController(
private val filmRepository: FilmDomaRepository
) {
@GetMapping
fun index(): List = ...
@PostMapping
fun create(
@RequestBody @Validated filmParam: FilmParam
): Int {
open不要
springの
アノテーションは普
通に使える
Slide 20
Slide 20 text
@Service
class FilmApplicationService(
private val filmRepository: FilmDomaRepository
) {
@Transactional
fun create(command: FilmCommand): Int {
@Repository
class FilmDomaRepository(
private val filmDao: FilmDao
) {
DI
Slide 21
Slide 21 text
@Configuration
class ObjectMapperConfig {
@Bean
fun objectMapper(): ObjectMapper
= ObjectMapper()
.registerModule(JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.registerModule(KotlinModule())
}
Config
Slide 22
Slide 22 text
SpringSecurity
@Configuration
@EnableAuthorizationServer
class Oauth2AuthorizationServerConfig(
private val authManager: AuthenticationManager,
private val dataSource: DataSource
) : AuthorizationServerConfigurerAdapter() {
@Bean
fun passwordEncoder(): BCryptPasswordEncoder
= BCryptPasswordEncoder()
Spring周辺の
ライブラリも
問題なく使える
Slide 23
Slide 23 text
SpringFox(Swagger)
@Configuration
@EnableSwagger2
class SwaggerConfig {
@Bean
fun apiV1Document(): Docket
= Docket(DocumentationType.SWAGGER_2)
.groupName("api v1")
.select()
.paths(PathSelectors.ant("/api/v1/**"))
.build()
}
Slide 24
Slide 24 text
No content
Slide 25
Slide 25 text
Kotlin x Jackson
Slide 26
Slide 26 text
data class FilmResource(
var name: String = "",
var isAdmin: Boolean = false,
var companyId: Int = 0
)
APIへのリクエスト(Json)をKotlinへマッピング
Jacksonは
デフォルト値ありの
コンストラクタを要
求
デフォルト値は使い
たくないのに。。
Slide 27
Slide 27 text
こうしたい
data class FilmResource(
val name: String,
val isAdmin: Boolean,
val companyId: Int
)
val source = FilmSource(film)
val json = objectMapper.writeValueAsString(source)
val indexRequest = IndexRequest(INDEX, TYPE, id)
.source(json, XContentType.JSON)
ElasticSearchとJsonやり取りする時も嬉しい
data class => json
Slide 31
Slide 31 text
searchResponse.hits.map { hit ->
val json = hit.sourceAsString
val filmSource: FilmSource = objectMapper.readValue(json)
}
ElasticSearchとJsonやり取りする時も嬉しい
json => data class
Kotlinの部分: Repository
@Repository
class FilmDomaRepository(
...
) {
fun findAll(): List {
val entities = filmDao.selectAll()
return Film.createByFilmEntities(entities)
}
Java(DomaのEntity)からKotlin(Model,
ValueObject)に
マッピング
Slide 48
Slide 48 text
Kotlinの部分: Model, ValueObject
class Film(
val id: Int? = null,
val title: String,
val description: String?,
val language: Language,
val actors: List,
val categories: List
) {
...
Slide 49
Slide 49 text
Kotlinの部分: Service
@Service
class FilmApplicationService(
...
) {
@Transactional
fun create(command: FilmCommand): Int {
val film = Film(
command = command,
language = langRepo.findById(command.languageId) ?: throw NotFoundException(),
actors = actorRepo.findByIds(command.actorIds),
categories = categoryRepo.findByIds(command.categoryIds)
)
val filmId = filmRepo.store(film)
mailService.sendCreated(film)
return filmId
}
Slide 50
Slide 50 text
Kotlinの部分: Controller
@RestController
@RequestMapping("/api/v1/films")
class FilmRestController(
private val filmRepository: FilmDomaRepository
) {
@GetMapping
fun index(): List
= filmRepository.findAll().map(::FilmResource)
Slide 51
Slide 51 text
よく触る部分は
全部Kotlin!
Slide 52
Slide 52 text
まとめ
● Kotlin x Spring BootでAPIサーバーは特に問題なく作れる
● kotlin-springプラグインのおかげでopen不要
● jackson-module-kotlinのおかげでdata classとのマッピングが楽に
● doma2はKotlinを実験的にサポート
○domaのentityをKotlinにできる。だが、kaptの不安定な挙動リスクあり
● 私達はdoma2の層をjavaにした
○ドメイン層、アプリケーション層はKotlinなのでほぼKotlin
● Kotlinかわいい(^ω^)ペロペロ
Slide 53
Slide 53 text
エムスリー love Kotlin
● 別件のリニューアルにもサーバーサイドKotlinを採用予定
● 新規Androidアプリ開発はKotlin
● 新規Webアプリ開発の際にも積極的にKotlinを検討