はじめに
最近GoogleがAndroidで公式サポートすることを表明したのでやってみました。
乗るしかない、このビッグウェーブに。
実はただの備忘録です。
Spring Boot自体案件で使ったことがあっても、構築するのは初めてな上に、
Kotlinの本を読み切る前に手を動かしたため、かなり適当な感じが拭えないです。
指摘があれば是非お願いします。
あと、今回はSpring Initializrで作ったひな形を使ってます。
使用環境
- macOS 10.12.5
- IntelliJ Idea 2017.1.3
- Java 1.8
- Kotlin 1.1.2
- Spring Boot 1.5.3 RELEASE
Spring Fox(SwaggerUI)の設定
動作確認にSwaggerUIを使いたいので以下のdependenciesをbuild.gradle
に追記。
// Spring Fox/Swagger
compile "io.springfox:springfox-swagger2:2.6.0"
compile "io.springfox:springfox-swagger-ui:2.6.0"
あと、DemoApplication.kt
と同じ階層にSwaggerConfiguration.kt
を以下の内容で配置。
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import springfox.documentation.swagger2.annotations.EnableSwagger2
import springfox.documentation.builders.RequestHandlerSelectors
import springfox.documentation.spi.DocumentationType
import springfox.documentation.spring.web.plugins.Docket
@EnableSwagger2
@Configuration
class SwaggerConfiguration {
@Bean
fun customDocket(): Docket {
return Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
.build()
}
}
Bodyの作成
今回はめんどくさいので受け取るのも返すのも同じPerson
とします。
class Person(
var name: String = "",
var age: Int = 0
)
以下の記述だとJsonMappingException
でエラーになりました。
エラー読む限りだとデフォルトコンストラクタを拾えてないっぽいので、この書き方だとデフォルトコンストラクタ不可視になっちゃうんですかね。
どっかでそんな記述を見た記憶がありますが…。
// これだとJsonMappingExceptionが発生する。
class Person(
var name: String,
var age: Int
)
Controllerの作成
import com.example.demo.body.Person
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping(value = "hello")
class HelloController {
@RequestMapping(value = "/person", method = arrayOf(RequestMethod.POST))
fun getPerson(@RequestBody person: Person): Person {
return Person(person.name, person.age)
}
}
動作確認
GradleのbootRun
タスクを叩いて起動できたら、SwaggerUIからリクエストを投げましょう。
結果
TODO
-
@Range
とかValidate系のアノテーションのメンバへの適用- 書き方の問題っぽい
- 省いたところもやってみる
- SecurityとかDBアクセスとか
Spring Annotationsを使う
Stack Overflowに載ってました!
…あれ?なんかKotlinの思想的にはイマイチなのでは…?
とりあえずやったことは以下の通りです。
- メンバに
@field:<任意のSpring Annotation>
を付与する。 - 以下のコンストラクタを
constructor
として定義する。- パラメータなしのコンストラクタ(デフォルトコンストラクタの代替)
- パラメータありのコンストラクタ
※任意。無くても動作します。
Bodyの修正
import org.hibernate.validator.constraints.Range
import javax.validation.constraints.NotBlank
class Person {
@field:NotBlank
var name: String
@field:Range(min = 18)
var age: Int
// 💩💩💩コンストラクタ💩💩💩
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
// 💩💩💩デフォルトコンストラクタの代替💩💩💩
constructor() {
this.name = ""
this.age = 0
}
}
Controllerの修正
引数に@Valid
を加えるだけです。
import com.example.demo.body.Person
import org.springframework.web.bind.annotation.*
import javax.validation.Valid
@RestController
@RequestMapping(value = "hello")
class HelloController {
@RequestMapping(value = "/person", method = arrayOf(RequestMethod.POST))
fun getPerson(@Valid @RequestBody person: Person): Person {
return Person(person.name, person.age)
}
}
動作結果2
{
"timestamp": 1495557375614,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.bind.MethodArgumentNotValidException",
"errors": [
{
"codes": [
"NotBlank.person.name",
"NotBlank.name",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"person.name",
"name"
],
"arguments": null,
"defaultMessage": "name",
"code": "name"
}
],
"defaultMessage": "may not be empty",
"objectName": "person",
"field": "name",
"rejectedValue": "",
"bindingFailure": false,
"code": "NotBlank"
},
{
"codes": [
"Range.person.age",
"Range.age",
"Range.int",
"Range"
],
"arguments": [
{
"codes": [
"person.age",
"age"
],
"arguments": null,
"defaultMessage": "age",
"code": "age"
},
9223372036854776000,
18
],
"defaultMessage": "must be between 18 and 9223372036854775807",
"objectName": "person",
"field": "age",
"rejectedValue": 17,
"bindingFailure": false,
"code": "Range"
}
],
"message": "Validation failed for object='person'. Error count: 2",
"path": "/hello/person"
}
まとめ
Kotlinでも当然ながらSpringの基本機能は問題なく使えそうです。
ただ、アノテーション周りはいまいちな感じがするので、このあたりはもう少し調べていきたいですね。
あと残りのTODOも。