B-Teck!

お仕事からゲームまで幅広く

【Kotlin】JerseyをKotlinで動かす その2 パラメータの取扱編

前回の記事 beatdjam.hatenablog.com

前回はJerseyの環境づくりと起動方法、Kotlinへの変換について書きました。
今回は各種リクエストパラメータをどうやって取り扱うかを説明します。

準備

今回の記事の内容を扱うにあたり、新しいResouceクラスを作成しましょう。
下記の形でParametersResource.ktを作成します。
このクラスには @Path("parameters") アノテーションがついているので、
http://localhost:8080/myapp/parameters に対応するクラスとなります。
クラスに@Pathがついている状態でメソッドにも@Pathがついているとき、
クラスのpath/メソッドのpathに対応します。

package com.example

import com.example.form.BeanParamSample
import java.nio.charset.Charset
import javax.validation.Valid
import javax.ws.rs.*
import javax.ws.rs.core.MediaType

/**
 * Root resource (exposed at "myresource" path)
 */
@Path("parameters")
class ParametersResource {

}

HTTPリクエストのクエリ

HTTPリクエストのクエリに含まれている値を利用するには、@QueryParam を使います。
例)
@QueryParam("parameter") parameter: String?

http://localhost:8080/myapp/parameters/queryparam?parameter=hoge

    @GET
    @Path("/queryparam")
    @Produces(MediaType.TEXT_PLAIN)
    fun queryParam(@QueryParam("parameter") parameter: String?): String {
        return if (parameter.isNullOrEmpty()) {
            "Parameter is Empty."
        } else parameter
    }

クエリをdata classに対応させる

前述したQueryParamをdata classのフィールドに定義します。
これを、対応させたいResourceクラスで@BeanParam アノテーションをつけて記述すると、
リクエスト時に自動でdata classに格納してくれるようになります。
後述する @PathParam@FormParamでも利用できるので覚えておきましょう。

また、JerseyではJavaEEのBean Validationという仕組みが利用できます。
@field:NotNull@field:NotEmpty などのバリデーション用のアノテーションを設定すると、
正しくないリクエストに対して、自動で400 Bad Requestを返却してくれるものです。

data class BeanParamSample (
        @QueryParam("parameter1")
        val parameter1: String?,

        @QueryParam("parameter2")
        @field:NotNull
        val parameter2: String?,

        @QueryParam("parameter3")
        @field:NotEmpty
        val parameter3: String?
)

 

@GET
@Path("/beanparam")
@Produces(MediaType.TEXT_PLAIN)
fun beanparam(@BeanParam @Valid parameter: BeanParamSample): String {
    return buildString {
        appendln(
                if (parameter.parameter1.isNullOrEmpty()) {
                    "Parameter is Empty."
                } else parameter.parameter1
        )
        appendln(parameter.parameter2)
        appendln(parameter.parameter3)
    }
}

Pathに含まれる値

HTTPリクエストのパスに含まれる値を利用するためには @PathParam アノテーションを利用します。
また、@Path の指定時にパラメータとしたい箇所を{}でくくる必要があります。
例)
@Path("/pathparam/{parameter1}
@PathParam("parameter") parameter: String?

http://localhost:8080/myapp/parameters/pathparam/hogehoge

@GET
@Path("/pathparam/{parameter}")
@Produces(MediaType.TEXT_PLAIN)
fun pathParam(@PathParam("parameter") parameter: String?): String {
    return if (parameter.isNullOrEmpty()) {
        "Parameter is Empty."
    } else parameter
}

リクエストパスからパターンに対応した値を取り出す

パターンに対応する文字列から複数を取り出すような事もできます。
{parameter1}.{parameter2} のようなパターンを設定すると、
0000.1234 のようなパスの00001234 をそれぞれ取得できます。
例)
@Path("/pathparam/{parameter1}.{parameter2}")
@PathParam("parameter1") parameter1: String?
@PathParam("parameter2") parameter2: String?

http://localhost:8080/myapp/parameters/pathparam/1234.5678

@GET
@Path("/pathparam/{parameter1}.{parameter2}")
@Produces(MediaType.TEXT_PLAIN)
fun pathParamSplit(
        @PathParam("parameter1") parameter1: String?,
        @PathParam("parameter2") parameter2: String?
): String {
    return (parameter1 ?: "") + "." +  (parameter2 ?: "")
}

リクエストパスから正規表現に対応した値を取り出す

パターンは正規表現で記述することもできます。
例)
@Path("/pathparam/regex/{regexMatched:.*}")
@PathParam("regexMatched") regexMatched: String?

http://localhost:8080/myapp/parameters/pathparam/regex/hogefuga/hoge

@GET
@Path("/pathparam/regex/{regexMatched:.*}")
@Produces(MediaType.TEXT_PLAIN)
fun pathParamRegex(@PathParam("regexMatched") regexMatched: String?): String {
    return if (regexMatched.isNullOrEmpty()) {
        "Not matched by regex."
    } else regexMatched
}

Formから送信されたリクエストを取得する

application/x-www-form-urlencoded 形式で送られたリクエストのパラメータは、
@FormParamで取り出すことができます。
例)
@FormParam("form1") form1param : String?
@FormParam("form2") form2param : String?

POSTなのでブラウザから直接たたけないため、CLI上で下記を叩いてください。
curl -d "form1=form1text" -d "form2=form2text" http://localhost:8080/myapp/parameters/formparam

@POST
@Path("/formparam")
@Produces(MediaType.TEXT_PLAIN)
fun formParam(
        @FormParam("form1") form1param : String?,
        @FormParam("form2") form2param : String?
): String {
    return buildString {
        appendln("form1 : $form1param")
        appendln("form2 : $form2param")
    }
}

ファイルアップロードに対応する

ほぼ以前書いた下記記事のままです。
【Kotlin/Java】Jersey2でファイルアップロードを扱う - B-Teck!

POSTなのでブラウザから直接たたけないため、CLI上で下記を叩いてください。
curl --header "Content-Type:application/octet-stream" -d "{"hoge": "fuga"}" http://localhost:8080/myapp/parameters/upload

@POST
@Path("/upload")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
@Produces(MediaType.TEXT_PLAIN)
fun upload(input : ByteArray): String {
    return input.toString(Charset.defaultCharset())
}

ここまでの作業

下記のタグまでが今回の記事の作業分です。
https://github.com/beatdjam/Jersey-On-Kotlin-Sample/tree/chapter2

作成したファイル
https://github.com/beatdjam/Jersey-On-Kotlin-Sample/blob/chapter2/src/main/kotlin/com/example/ParametersResource.kt
https://github.com/beatdjam/Jersey-On-Kotlin-Sample/blob/chapter2/src/main/kotlin/com/example/form/BeanParamSample.kt