Spring MVC コントローラの引数

Spring MVCのコントローラメソッドは、画面で入力されたパラメータ以外に、様々な情報を引数として受け取ることができます。

# アノテーションを使用して受け取る
メソッドの引数にアノテーションを指定することで受け取ることができる情報がいくつかあります。

## リクエストパラメータ
@RequestParamアノテーションを指定すると、URLに含まれるクエリパラメータや、メッセージボディーに含まれるポストパラメータを受け取ることができます。

```java
@GetMapping("/hello")
public String hello(@RequestParam("name") String name) {
```

ブラウザから「/hello?name=world」のように、URLにクエリーパラメータを指定することで、コントローラメソッドで、指定された値を取得することができます。

### required属性

リクエストパラメータは、デフォルトでは必須パラメータになります。パラメータの指定を任意にする場合、@RequestParamアノテーションのrequired属性にfalseを指定します。

```java
@GetMapping("/hello")
public String hello(@RequestParam(name = "name", required = false) String name) {
```

リクエストパラメータが指定されなかった場合、引数の値はnullになります。Java 8以降であれば、Optionalで受け取ることも可能です。

```java
@GetMapping("/hello")
public String hello(@RequestParam(name = "name", required = false) Optional<String> name) {
```

### defaultValue属性

リクエストパラメータが指定されなかった時のデフォルト値を指定することができます。
@RequestParamアノテーションのdefaultValue属性にデフォルト値を指定することで、リクエストパラメータが指定されていない場合は、このデフォルト値が引数に設定されます。

```java
@GetMapping("/hello")
public String hello(@RequestParam(name = "name", defaultValue = "") String name) {
```

## URLパスパラメータ
@PathVariableアノテーションを指定すると、URLに含まれる動的なパラメータを受け取ることができます。

```java
@GetMapping("/hello/{name}")
public String hello(@PathVariable("name") String name) {
```

URLマッピングで指定するURLに「{」と「}」で囲まれた部分がパラメータ名になり、@PathVariableアノテーションのvalue属性にパラメータ名を指定することで、URLの部分文字列を取得することができます。

受け取る変数は文字列型(String)である必要はありません。整数型、実数型を指定することもできます。

```java
@GetMapping("/hello/{age}")
public String hello(@PathVariable("age") Integer age) {
```

日時型で受け取ることもできます。その場合は、@DateTimeFormatアノテーションを指定して、受け取る日時の文字列表現の形式を指定します。

```java
@GetMapping("/hello/{date}")
public String hello(@PathVariable("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) java.util.Date date) {
```

### required属性

URLパスパラメータは、デフォルトでは必須パラメータになります。パラメータの指定を任意にする場合、@PathVariableアノテーションのrequired属性にfalseを指定します。

```java
@GetMapping("/hello/{name}")
public String hello(@PathVariable(name = "name", required = false) String name) {
```

ただし、これだけでは、パラメータが指定されていないURLは別のURLと認識され、404(Not Found)になってしまいます。URLマッピングにパラメータがないURLを追加して、パラメータの有無にかかわらず、コントローラのメソッドが呼び出されるようにします。

```java
@GetMapping({ "/hello", "/hello/{name}" })
public String hello(@PathVariable(name = "name", required = false) String name) {
```

パラメータが指定されなかった場合、引数の値はnullになります。Java 8以降であれば、Optionalで受け取ることも可能です。

```java
@GetMapping({ "/hello", "/hello/{name}" })
public String hello(@PathVariable(name = "name", required = false) Optional<String> name) {
```

## URL行列パラメータ
URLパスパラメータ内に名前と値をペアとした行列パラメータを含めることができます。行列パラメータは「;」で区切り、複数指定することができます。
次の例は、行列パラメータとして「sex」と「age」を指定した例です。

```
http://localhost:8080/hello/scott;sex=male;age=25
```

URL行列パラメータを使用する場合、removeSemicolonContentプロパティーにfalseを設定する必要があります。
Spring Bootを使用している場合、WebMvcConfigurerAdapterを継承した設定クラスのconfigurePathMatchメソッドをオーバーライドして、removeSemicolonContentプロパティーにfalseを設定します。

```java
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.util.UrlPathHelper;

@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}
```

@MatrixVariableアノテーションを指定すると、URLパスパラーメータに含まれる行列パラメータを受け取ることができます。

```java
@GetMapping("/hello/{name}")
public String hello(@MatrixVariable("age") Integer age) {
```

@MatrixVariableアノテーションのvalue属性に、URLパスパラメータに付随するURL行列パラメータ名を指定することで、行列パラメータの値を取得することができます。

受け取る変数は文字列型(String)である必要はありません。整数型、実数型を指定することもできます。

### pathVar属性

複数のURLパスパラメータに、同名のURL行列パラメータ名が存在する場合、@MatrixVariableアノテーションのpathVar属性でURLパスパラメータの名前を指定します。

```java
    @GetMapping("/hello/{name}/{father}")
    public String hello(
            @MatrixVariable(name = "age", pathVar = "name") Integer age,
            @MatrixVariable(name = "age", pathVar = "father") Integer fatherAge) {
```

次のURLに対してリクエストを発行します。

```
http://localhost:8080/hello/scott;age=25/tiger;age=50
```

コントローラーの引数「age」には「25」が、「fatherAge」には「50」が設定されます。

### required属性

URL行列パラメータは、デフォルトでは必須パラメータになります。パラメータの指定を任意にする場合、@MatrixVariableアノテーションのrequired属性にfalseを指定します。

```java
@GetMapping("/hello/{name}")
public String hello(@MatrixVariable(name = "age", required = false) Integer age) {
```

URL行列パラメータが指定されなかった場合、引数の値はnullになります。Java 8以降であれば、Optionalで受け取ることも可能です。

```java
@GetMapping("/hello/{name}")
public String hello(@MatrixVariable(name = "age", required = false) Optional<Integer> age) {
```

### defaultValue属性

URL行列パラメータが指定されなかった時のデフォルト値を指定することができます。
@MatrixVariableアノテーションのdefaultValue属性にデフォルト値を指定することで、URL行列パラメータが指定されていない場合は、このデフォルト値が引数に設定されます。

```java
@GetMapping("/hello/{name}")
public String hello(@MatrixVariable(name = "age", defaultValue = 0) Optional<Integer> age) {
```

## クッキーパラメータ
@CookieValueアノテーションを指定すると、クッキーパラメータを受け取ることができます。

```java
@GetMapping("/hello")
public String hello(@CookieValue("name") String name) {
```

ブラウザのクッキーに値が設定されている状態でリクエストを発行すると、コントローラメソッドで、指定された値を取得することができます。

### required属性

クッキーパラメータは、デフォルトでは必須パラメータになります。パラメータの指定を任意にする場合、@CookieValueアノテーションのrequired属性にfalseを指定します。

```java
@GetMapping("/hello")
public String hello(@CookieValue(name = "name", required = false) String name) {
```

クッキーパラメータが指定されなかった場合、引数の値はnullになります。Java 8以降であれば、Optionalで受け取ることも可能です。

```java
@GetMapping("/hello")
public String hello(@CookieValue(name = "name", required = false) Optional<String> name) {
```

### defaultValue属性

クッキーパラメータが指定されなかった時のデフォルト値を指定することができます。
@CookieValueアノテーションのdefaultValue属性にデフォルト値を指定することで、クッキーパラメータが指定されていない場合は、このデフォルト値が引数に設定されます。

```java
@GetMapping("/hello")
public String hello(@CookieValue(name = "name", defaultValue = "") String name) {
```

## リクエストヘッダ
@RequestHeaderアノテーションを指定すると、リクエストヘッダに含まれている各項目を受け取ることができます。

```java
@GetMapping("/hello")
public String hello(@RequestHeader("User-Agent") String userAgent) {
```

ブラウザからリクエストを発行することで、コントローラメソッドで、指定されたリクエストヘッダの項目を取得することができます。

### required属性

指定したリクエストヘッダの項目は、デフォルトでは必須項目になります。リクエストヘッダの項目の有無を任意にする場合、@RequestHeaderアノテーションのrequired属性にfalseを指定します。

```java
@GetMapping("/hello")
public String hello(@RequestHeader(name = "User-Agent", required = false) String userAgent) {
```

指定したリクエストヘッダの項目がなかった場合、引数の値はnullになります。Java 8以降であれば、Optionalで受け取ることも可能です。

```java
@GetMapping("/hello")
public String hello(@RequestHeader(name = "User-Agent", required = false) Optional<userAgent> name) {
```

### defaultValue属性

指定したリクエストヘッダの項目がなかった時のデフォルト値を指定することができます。
@RequestHeaderアノテーションのdefaultValue属性にデフォルト値を指定することで、指定したリクエストヘッダの項目がなかった場合は、このデフォルト値が引数に設定されます。

```java
@GetMapping("/hello")
public String hello(@RequestHeader(name = "User-Agent", defaultValue = "Mozilla/5.0") String userAgent) {
```

## リクエストボディー
@RequestBodyアノテーションを指定すると、リクエストボディーの内容をそのまま取得することができます。

```java
@PostMapping("/hello")
public String hello(@RequestBody String body) {
```

リクエストボディーを含むリクエストを発行することで、コントローラメソッドで、リクエストボディーの内容を取得することができます。

次のHTMLファイルから、POSTリクエストを発行して、コントローラーでリクエストボディーを取得してみます。

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
    <form action="hello" method="post">
        User: <input type="text" name="user" size="20"><br />
        Password: <input type="text" name="password" size="20"><br />
        <input type="submit" value="Login">
    </form>
</body>
</html>
```

入力欄「User」に「scott」、「password」に「tiger」を入力してリクエストを発行すると、コントローラーで@RequestBodyアノテーションを指定した引数の内容は、次のようになります。

```
user=scott&password=tiger
```

### required属性

リクエストボディーは、デフォルトでは必須項目になります。リクエストボディーの有無を任意にする場合、@RequestBodyアノテーションのrequired属性にfalseを指定します。

```java
@PostMapping("/hello")
public String hello(@RequestBody(required = false) String body) {
```

リクエストボディーがなかった場合、引数の値はnullになります。Java 8以降であれば、Optionalで受け取ることも可能です。

```java
@PostMapping("/hello")
public String hello(@RequestBody(required = false) Optional<String> body) {
```

## HTTPセッション属性
@SessionAttributeアノテーションを指定すると、HTTPセッションに保存されている属性値を取得することができます。

```java
@GetMapping("/hello")
public String hello(@SessionAttribute("age") Integer age) {
```

HTTPセッションに指定した属性名が設定されている状態でリクエストを発行すると、コントローラメソッドで、指定された属性名の値を取得することができます。

### required属性

HTTPセッションの属性は、デフォルトでは必須項目になります。HTTPセッションの属性の有無を任意にする場合、@SessionAttributeアノテーションのrequired属性にfalseを指定します。

```java
@PostMapping("/hello")
public String hello(@SessionAttribute(name = "age", required = false) Integer age) {
```

HTTPセッションの属性がなかった場合、引数の値はnullになります。Java 8以降であれば、Optionalで受け取ることも可能です。

```java
@PostMapping("/hello")
public String hello(@SessionAttribute(name = "age", required = false) Optional<Integer> age) {
```