LoginSignup
1
3

More than 3 years have passed since last update.

Micronaut リクエストバインディング

Last updated at Posted at 2020-07-24

Micronautのコントローラにて各種データの受け取り方(リクエストバインディング)についてまとめておきます。

公式ドキュメントがありますので、そちらも参考にしてみてください。
Micronaut -> 6.4 Simple Request Binding

環境

Micronaut Version: 2.0.0
Java: 11

リクエストパラメータ

リクエストパラメータを取得する場合はメソッドの引数にパラメータを指定するだけになります。

@Get("/hello{?name}")
// @Get("/value") // パラメータ名の省略も可能
public String hello(Optional<String> name) {
    return name.orElse("Hi!");
}

リクエストパラメータ名と変数名を変える場合

リクエストパラメータ名とJavaの変数名が異なる場合は、QueryValueを利用します。

@Get("/hello2{?first_name}")
public String hello2(@QueryValue("first_name") Optional<String> firstName) {
    return firstName.orElse("Hi!");
}
$ curl "http://localhost:8080/queryparam/hello2?first_name=taro"
taro

リクエストパラメータ自体を必須項目とする場合

上記2つのメソッドは、リクエストパラメータを指定していなくてもエラーになりませんでした。
リクエストパラメータの指定がない場合にエラーにするにはOptionalを利用しないことで可能になります。

同時に該当のパラメータの値がNullを許容するかも判断しています。
今回はNullを許容しないため、ControllerにValidatedアノテーションを、メソッドのnameパラメータにNotBlankアノテーションを付与しました。

@Controller("/queryparam")
@Validated
public class QueryParamController {
    @Get("/hello3")
    public String hello3(@NotBlank String name) {
        return name;
    }
}
$ curl "http://localhost:8080/queryparam/hello3"
{"message":"Required argument [String name] not specified","path":"/name","_links":{"self":{"href":"/queryparam/hello3","templated":false}}}

$ curl "http://localhost:8080/queryparam/hello3?name="
{"message":"name: must not be blank","_links":{"self":{"href":"/queryparam/hello3?name=","templated":false}}}

$ curl "http://localhost:8080/queryparam/hello3?name=Taro"
Taro

リクエストパラメータをBeanにバインディング

リクエストパラメータをBeanにバインディングするには、{?pojo*}を使用して、格納したいBean変数にRequestBeanアノテーションを付与することで実現できます。

Controller
@Get("/hello4{?queryParamReq*}")
public String hello4(@NotBlank @RequestBean QueryParamReq queryParamReq) {
    return queryParamReq.getFirstName().orElse("sei") + " " +
           queryParamReq.getLastName().orElse("mei") + " さん";
}

BeanにはIntrospectedアノテーションを付与します。

QueryParamReq
@Introspected
public class QueryParamReq {
    @QueryValue("first_name")
    private Optional<String> firstName;
    @QueryValue("last_name")
    private Optional<String> lastName;

    public QueryParamReq(Optional<String> firstName, Optional<String> lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Optional<String> getFirstName() {
        return this.firstName;
    }

    public Optional<String> getLastName() {
        return this.lastName;
    }
}
$ curl "http://localhost:8080/queryparam/hello4?first_name=suzuki&last_name=taro"
suzuki taro さん

URLパスパラメータ

PathVariableアノテーションを利用することで、URLパスパラメータを指定可能です。

@Get("/hello/{name}")
public String hello(@PathVariable String name) {
    return name;
}

URLパスパラメータをBeanにバインディング

今度はURLパスパラメータもBeanにバインディングしてみます。

Controller
@Get("/hello2/{first_name}/{last_name}")
public String hello2(@RequestBean PathVariableReq pathVariableReq) {
    return pathVariableReq.getFirstName().orElse("sei") + " " +
           pathVariableReq.getLastName().orElse("mei") + " さん";
}
PathVariableReq
@Introspected
public class PathVariableReq {
    @PathVariable("first_name")
    private Optional<String> firstName;
    @PathVariable("last_name")
    private Optional<String> lastName;

    public PathVariableReq(Optional<String> firstName, Optional<String> lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Optional<String> getFirstName() {
        return this.firstName;
    }

    public Optional<String> getLastName() {
        return this.lastName;
    }
}

クッキーパラメータ

クッキーパラメータはCokieValueアノテーションで取得可能です。

@Get("/hello")
public String hello(@CookieValue("name") Optional<String> name) {
    return name.orElse("Hi!");
}
$ curl "http://localhost:8080/cookie/hello" -b "name=taro"
taro

リクエストヘッダーパラメータ

リクエストヘッダーを取得するには、Headerアノテーションを付与します。

@Get("/hello")
public String hello(@Header("User-Agent") String userAgent) {
    return userAgent;
}
$ curl "http://localhost:8080/header/hello" 
curl/7.54.0

リクエストボディ

Bodyの値を取得するにはBodyアノテーションを付与します。

@Post(value = "/hello", consumes = MediaType.TEXT_PLAIN)
public String hello(@Body Optional<String> name) {
    return name.orElse("Hi!");
}
$ curl -X POST "http://localhost:8080/body/hello" -d "taro" -H "Content-Type: text/plain"
taro

BodyのjsonをBeanにバインディング

BodyのjsonをBeanにバインディングする場合は、BodyアノテーションをBeanに付与すれば良いです。

Controller
@Post("/hello2")
public String hello2(@Body BodyParamReq bodyParamReq) {
    return bodyParamReq.getFirstName().orElse("sei") + " " +
           bodyParamReq.getLastName().orElse("mei") + " さん";
}

BodyのjsonはJacksonを利用して変換しているため、jsonカラム名とBeanフィールド名が異なる場合にはJsonPropertyを利用して変換してあげればいいです。

BodyParamReq
@Introspected
public class BodyParamReq {
    @JsonProperty("first_name")
    private Optional<String> firstName;
    @JsonProperty("last_name")
    private Optional<String> lastName;

    public BodyParamReq(Optional<String> firstName, Optional<String> lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Optional<String> getFirstName() {
        return this.firstName;
    }

    public Optional<String> getLastName() {
        return this.lastName;
    }
}
$ curl -X POST "http://localhost:8080/body/hello2" -d '{ "first_name": "suzuki", "last_name": "taro" }' -H "Content-Type: application/json"
suzuki taro さん

Bodyのパラメータをそれぞれの変数にバインディング

Body内のパラメータをそれぞれの変数にバインディングするには、PostアノテーションのconsumesにMediaType.APPLICATION_FORM_URLENCODEDを指定してあげて、Bodyアノテーションにパラメータ名を指定すればバインディングされます。

@Post(value = "/hello3", consumes = MediaType.APPLICATION_FORM_URLENCODED)
    public String hello3(@Body("first_name") Optional<String> firstName, @Body("last_name") Optional<String> lastName) {
        return firstName.orElse("sei") + " " +
                lastName.orElse("mei") + " さん";
    }
$ curl -X POST "http://localhost:8080/body/hello3" -d "first_name=suzuki" -d "last_name=taro" -H "Content-Type: application/x-www-form-urlencoded"
suzuki taro さん

セッションを利用

セッションを利用する場合はmicronaut-sessionを利用します。

implementation("io.micronaut:micronaut-session")
Controller
@Post(value = "/hello", consumes = MediaType.APPLICATION_FORM_URLENCODED)
public String setName(Session session, @Body Optional<String> name) {
    if (name.isPresent())
        session.put("name", name.get());
    return name.orElse("Hi!");
}

@Get("/hello")
public String hello(Session session) {
    return session.get("name", String.class).orElse("Hi!");
}
$ curl -v -X POST "http://localhost:8080/session/hello" -d "name=taro" -H "Content-Type: application/x-www-form-urlencoded"
一部省略
< HTTP/1.1 200 OK
< set-cookie: SESSION=NTJhZjY1MDAtMDhmZC00Y2YwLWFmMjctMTMxZjcwMDRhZjBi; Path=/; HTTPOnly
一部省略
taro

$ curl "http://localhost:8080/session/hello" -b "SESSION=NTJhZjY1MDAtMDhmZC00Y2YwLWFmMjcMxZjcwMDRhZjBi"
taro

Sessionの値をメソッド変数に格納する

Sessionの値をそのままメソッド変数に格納するにはSessionValueアノテーションを利用します。

@Post(value = "/hello", consumes = MediaType.APPLICATION_FORM_URLENCODED)
public String setName(Session session, @Body Optional<String> name) {
    if (name.isPresent())
        session.put("name", name.get());
    return name.orElse("Hi!");
}

@Get("/hello2")
@SessionValue("name")
public String hello2(@SessionValue Optional<String> name) {
    return name.orElse("Hi!");
}
$ curl -v -X POST "http://localhost:8080/session/hello" -d "name=taro" -H "Content-Type: application/x-www-form-urlencoded"
一部省略
< HTTP/1.1 200 OK
< set-cookie: SESSION=YzYyMjM4YjMtYTczYy00NGRiLTk3MmQtZTNjZmU0YzhhY2Jm; Path=/; HTTPOnly
一部省略
taro

$ curl "http://localhost:8080/session/hello2" -b "SESSION=YzYyMjM4YjMtYTczYy00NGRiLTk3MmQtZTNjZmU0YzhhY2Jm"
taro

参考

Micronaut -> 6.4 Simple Request Binding
Spring MVC コントローラの引数 記事の形など参考にさせていただきました。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3