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アノテーションを付与することで実現できます。
@Get("/hello4{?queryParamReq*}")
public String hello4(@NotBlank @RequestBean QueryParamReq queryParamReq) {
return queryParamReq.getFirstName().orElse("sei") + " " +
queryParamReq.getLastName().orElse("mei") + " さん";
}
BeanにはIntrospectedアノテーションを付与します。
@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にバインディングしてみます。
@Get("/hello2/{first_name}/{last_name}")
public String hello2(@RequestBean PathVariableReq pathVariableReq) {
return pathVariableReq.getFirstName().orElse("sei") + " " +
pathVariableReq.getLastName().orElse("mei") + " さん";
}
@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に付与すれば良いです。
@Post("/hello2")
public String hello2(@Body BodyParamReq bodyParamReq) {
return bodyParamReq.getFirstName().orElse("sei") + " " +
bodyParamReq.getLastName().orElse("mei") + " さん";
}
BodyのjsonはJacksonを利用して変換しているため、jsonカラム名とBeanフィールド名が異なる場合にはJsonPropertyを利用して変換してあげればいいです。
@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")
@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 コントローラの引数 記事の形など参考にさせていただきました。