POSTで呼ばれた場合のリクエスト情報の取得について（Spring Boot）

# はじめに
Spring Bootで開発している際にPOSTでリクエストされた場合の、リクエスト情報の取得方法について調べたので備忘録として記載します。

# 目次
- Spring BootでPOSTリクエスト
- POSTリクエストとは
- リクエスト情報を取得する
- まとめ


# Spring BootでPOSTリクエスト
まず初めに、POSTリクエストを受け付ける簡単なSpring Bootアプリケーションを実装します。

```java
package com.example.demo;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@RestController
public class DemoController {

  @RequestMapping(value = "/demo", produces = {"application/json"},
      method = {RequestMethod.GET, RequestMethod.POST})
  public String getDemo(){

    HttpServletRequest request = ((ServletRequestAttributes) Objects
        .requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

    // getの場合はここでパラメータを取得
    String queryString = request.getQueryString();

    if (queryString == null || queryString.isEmpty()) {
      // postの場合はここでパラメータを取得
      List<Entry<String, Object>> list = getRequestParameters(request);
      queryString = getQueryStringFromParameterMap(list);
    }

    return queryString;
  }
  
  public static List<Entry<String,Object>> getRequestParameters(HttpServletRequest request) {
    List<Entry<String,Object>> requestParameters = new ArrayList<>();
    Enumeration<String> parameterNames = request.getParameterNames();
    while (parameterNames.hasMoreElements()) {
      String name = parameterNames.nextElement();
      requestParameters.add(Map.entry(name, request.getParameterValues(name)[0]));
    }
    return requestParameters;
  }

  public static String getQueryStringFromParameterMap(List<Entry<String,Object>> parameterMap) {
    StringBuilder queryString = new StringBuilder();
    for (Entry<String,Object> parameter : parameterMap) {
      if (queryString.length() > 0)
        queryString.append("&");
      queryString.append(parameter.getKey()).append("=")
          .append(URLEncoder.encode(parameter.getValue().toString(), StandardCharsets.UTF_8));
    }
    return queryString.toString();
  }
}

```

# POSTリクエスト
いくつかの方法でPOSTリクエストしてみます。
#### パターン１

```
$ curl -X POST "http://localhost:8080/demo" -H "Content-Type: application/x-www-form-urlencoded" --data-raw "param=456"
$ param=456
```

#### パターン２

```
$ curl -X POST "http://localhost:8080/demo" --data-raw "param=789"
$ param=789
```

#### GETリクエスト
念のためGETでもリクエストしてみます。

```
$ curl -X GET "http://localhost:8080/demo?param=123"
$ param=123
```

# リクエスト情報を取得する
POSTでリクエストされたときのパラメータが取得できていますね。
それでは少し取得処理を見ていきましょう。
`getRequestParameters()` 内部の `request.getParameterNames()` で取得していますね。

```
  public static List<Entry<String,Object>> getRequestParameters(HttpServletRequest request) {
    List<Entry<String,Object>> requestParameters = new ArrayList<>();
    Enumeration<String> parameterNames = request.getParameterNames(); <--★ここです。
    while (parameterNames.hasMoreElements()) {
      String name = parameterNames.nextElement();
      requestParameters.add(Map.entry(name, request.getParameterValues(name)[0]));
    }
    return requestParameters;
  }
```

Spring Bootでは、`org.apache.catalina.connector` を利用しているため実装的にはこちらの `getParameterNames()` になります。
ref. [getParameterNames](https://github.com/apache/tomcat/blob/main/java/org/apache/catalina/connector/Request.java#L1152)


```
    public Enumeration<String> getParameterNames() {

        if (!parametersParsed) {
            parseParameters();
        }

        return coyoteRequest.getParameters().getParameterNames();

    }
```

# まとめ
簡単ではありますが、POSTリクエストからパラメータを取得する方法を記載しました。
やり方はいろいろあると思うので、この他にも効率的なやり方があるかもしれませんので、ご知見のある方は是非教えてください。