以前から大分アツいAndroidでのKotlin話であるが、今回はKotlinとSpring Bootを使って簡単にjsonを吐くAPIアプリケーションを作ってみたいと思う。
KotlinについてとSpring Framework,Spring Bootに関しては特記しないので各々よしなに。
Spring Initializerという素晴らしいものがあるのでこれを使っていく。
今回は
で作成。
依存にはweb
とjpa
を追加している。
1 2 | compile('org.springframework.boot:spring-boot-starter-data-jpa') compile('org.springframework.boot:spring-boot-starter-web') |
がbuild.gradleに追加される形になる。
クラスに@RestController
アノテーションを付けるとそのクラスがいい感じにコントローラーとして認識される。
リクエストに対するメソッドのbindは@RequestMapping(PATH, REQUEST_METHOD)
というアノテーションをメソッドに対して付与する。
1 2 3 4 5 | @RestController class IndexController { @RequestMapping("/", arrayOf(RequestMethod.GET)) fun index(): String = "Hello Spring with Kotlin!" } |
このクラスを作った状態で./gradlew bootRun
をしてあげるとlocalhost:8080
でHello Wpring with Kotlin!
を表示される。
単に静的なものを返してもアレなので、DBに保存してあるデータをAPIが叩かれたらjsonで吐くみたいなことをしたい。
Postgresqlで行っていく。
Spring Initializerで依存追加したSpring Data JPAというのがとりあえず強いのでそれを使う。
postgresqlを使うときは更に依存に runtime('org.postgresql:postgresql')
を追加してあげるといい。
そしてKotlinを使う場合、EntityとかのモデルクラスをDataClassとしてそのまま作成するとデフォルトコンストラクターが〜みたいなエラーを吐くのでbuild.gradleに以下を追加してあげる。
1 2 | classpath ("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}") apply plugin: "kotlin-jpa" |
該当のstackoverflowはここ
更にDataSourceの設定として、src/main/resource
の下にconfig
ディレクトリを作成し、application.yml
を追加してそこにDBへの接続情報を書き込む。
1 2 3 4 5 6 | spring: datasource: url: jdbc:postgresql://localhost/[データベース名] username: username password: password driverClassName: org.postgresql.Driver |
これでDBに接続する準備は完了。次に必要なクラスとインターフェースを作っていく。
まずサンプルを見てもらったほうが理解しやすいのでサンプルコード
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Entity @Table(name = "テーブル名") data class User ( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Int, @Column(name = "name") val name: String, @Column(name = "post_code") val postCode: String ) |
@Column
アノテーションをつけてあげると、スネークケースとキャメルケースの変換をしてくれる(Androidでよく使うところとしてはMoshiとかgsonとかのあんな感じ)。
@GeneratedValue
を付与すると、値を指定しなくても自動される。@Id
をつけるとプライマリーキーとして指定することができる。
これがSpring Data JPAの強さ(?)
1 | interface UserRepository : JpaRepository<User, Int> {} |
これだけ書いておけばOK。JpaRepository
を継承していればSQLを書かずにメソッド名からいい感じにSQL文を作ってくれてよしなにしてくれるらしい。
例えば名前からselectしたいメソッドが欲しい場合は
1 2 3 | interface UserRepository : JpaRepository<User, Int> { fun findByName(name: String): List<User> } |
とfindBy〜
とか書いておけばいい感じに勝手にしてくれる。もちろんASCとかDESCとかでの並び替え等々や複雑なものも書ける。参考
あまりに複雑にするとメソッド名が長くなりすぎると思うのでそこはいい感じにしてほしい。
RepositoryとControllerを繋ぐ。
1 2 3 4 5 6 7 8 9 10 | @Service @Transactional class UserService { @Autowired lateinit var repository: UserRepository fun selectAll(): Lise<User> = repository.findAll(Sort(Sort.Direction.ASC, "id")) fun selectFromName(name: String): List<User> = repository.findByName(name) } |
こんな感じで書いてあげる。findAll()
メソッドはJpaRepository
に最初から何も書かずとも生えてるので追加しなくてもOK。
このサービスでのselectAll()
はfindAll()
したものをid昇順でソートしてControllerに渡すように書いている。
@Autowired
を書いておけば依存注入を勝手にいい感じにやってくれる。あまりにもいい感じにやってくれすぎててこわい。
最後にこれを作るとjsonを吐くAPIの完成 上で書いたようなControllerを作ってあげればよい。
1 2 3 4 5 6 7 8 9 10 11 12 13 | @RestController @RequestMapping("/user") class UserController { @Autowired lateinit var service: UserService @RequestMapping("/all", arrayOf(RequestMethod.GET)) fun selectAll(): List<User> = service.selectAll() @RequestMapping("/name", arrayOf(RequestMethod.GET)) fun selectFronName(@RequestParam("name")name: String): List<User> = service.selectFromName(name) } |
こんな感じ。
最初のサンプルでは使わなかったが、クラスに@RequestMapping
アノテーションを付けると、そのクラスがそのパスにマッピングされる。
なので/user/all
がfun selectAll()
にマッピングされていることになる。
GETでのリクエストパラメータを受け取りたいときは、メソッドの引数に@RequestParam("パラメータ名")変数名: 型
を書いてあげればOK。
上記のコントローラーを作れば
localhost:8080/user/all
localhost:8080/user/name?name="なまえ"
でGETするといい感じにDBに入っているデータが適切に取れる。
さくっととは言い難いかもしれないが、Kotlinを使っていい感じにAPIアプリケーションを作ることが出来た。
Androidアプリを業務趣味問わずKotlinで書いてる人でAPIが欲しい!って思ったらさくっと作れるのではなかろうか。試してみて欲しい(自分はやってる)。
さくっと作るというとKotlin/ktorのほうが適していると思うので、こちらもそのうちやってみてまとめようと思う。
<< Kotlin Android Extensionsを使ってfindViewByIdとさよならする OnePlus5が最高すぎる件について >>
2018やぎ小屋