ゼロから始めるSpring Boot　その２

####目標
複数回に分けて実施予定です。

1. SpringBootとは何かをざっくり知る
1. 環境構築＆Hello World!を表示させる
1. **パラメータやオブジェクトの受け渡しをする**<font color="red">　←今回やること</font>
1. 他の機能にも触れてみる

####前置き
前回はHello Worldを表示するために下の２つをやりました。

- `@RestController`で文字列を表示
- `@Controller`でindex.htmlを表示

プロジェクトは前回作ったものを引き続き使用します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/0ad100c1-803a-ac0f-e5f4-478a89c6c1ed.png" width="75%">
具体的には以下のようなことをやります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/eb880e69-f7f5-78af-b3ba-cabf9d1db33d.png" width="75%">
これを実現するためには、主に2種類の方法があります。
まずは`@RequestParam`から使っていきましょう。
#パラメータを受け渡そう（RequestParam編）
`index.html`の`<body>`部分を以下のように書き換えます。

```html:index.html
<body>
<form action="/hello" method="get">
名前：
<input type="text" name="username">
<input type="submit" value="送信">
</form>
</body>
```
<details>
<summary>各種タグの説明についてはここをクリック。</summary><div>

|タグ|要素名|内容|
|:-:|:-:|:-:|
|form|action|リクエストを送るURLを指定。|
||method|送信方法をGET、POSTから選択して指定。|
|input|type="text"|テキストフィールド。|
||name|パラメータに付ける名前。java側で取得する際に使用。|
||type="submit"|パラメータを送信するためのボタン。|
||value|コンテンツ（テキストフィールドやボタンなど）の中身に表示させる文字列を指定。|

</div>
</details>

続けて`DemoController.java`に以下のコードを追加します。

```java:DemoController.java
package com.example.demo;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class DemoController {
	
	//前回作成したhelloメソッドと同じです。（メソッド名が被るのでindexに変更）
	@RequestMapping(value="/",method=RequestMethod.GET)
	public ModelAndView index() {
		ModelAndView mav=new ModelAndView();
		mav.setViewName("/index");
		return mav;
	}
	
	//今回追加するメソッドです。
	@GetMapping("/hello")
	public ModelAndView hello(@RequestParam String username,ModelAndView mav) {
		mav.addObject("username",username);
		mav.setViewName("/hello");
		return mav;
	}
}
```

[ModelAndViewの機能は前回の記事へ！](https://qiita.com/hatopo/items/ecc16fdc757fc8cc8d55#modelandview)

####`@RequestParam`
引数の先頭に記述。これを付けることにより、リクエストパラメータの値が自動的に変数に格納されます。また、書き方が色々あるのでまとめて紹介します。
例として、送られてくるパラメータの名前は「`username`」とします。

- `@RequestParam` String <font color="red">username</font><br>
今回使用している書き方です。変数名（赤字）と、受け取りたいパラメータの名前を同じにする必要があります。変数名と同じパラメータが存在しないとエラーになります。

```java:記述例
@RequestParam String username //OK
@RequestParam String name //NG
```
- `@RequestParam("username")` String <font color="red">username</font><br>
一番無難な書き方です。アノテーション側で、受け取りたいパラメータの名前を指定します。存在しない名前を指定してしまうとエラーになります。この時、変数名は任意の名前でOKです。

```java:記述例
@RequestParam("username") String username //OK
@RequestParam("username") String name //OK
@RequestParam("name") String username //NG
```

- `@RequestParam(value="username",required=false)` String <font color="red">username</font><br>
あまり出てきません。`value`でパラメータの名前を、`required`でパラメータの存在を必須条件にするかどうかが選べます。デフォルトはtrueです。<br>
falseにすると指定したパラメータが存在しなくてもエラーになりません（当然パラメータの受け渡しは出来ませんが・・・）。これも変数名は任意の名前でOKです。

```java:記述例
@RequestParam(value="username",required=false) String username //OK
@RequestParam(value="name",required=false) String name //OK でも受け渡しは出来ない
@RequestParam(value="name",required=true) String name //NG
```

***
続いてパラメータを受け取るHTMLファイルを作成します。
`index.html`と同じフォルダに`hello.html`という名前でHTMLファイルを作成し、中身を以下のように書き換えてください。

```html:hello.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<span th:text="${username}"></span>さん、Hello World!
</body>
</html>
```

- **`<html xmlns:th="http://www.thymeleaf.org">`**<br>
この記述によってThymeleafの機能を`th`から始まるタグ名で呼び出せるようになります。<br>
Thymeleafってなんだ？については[前回の記事](https://qiita.com/hatopo/items/ecc16fdc757fc8cc8d55#%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)や[公式ドキュメント](https://www.thymeleaf.org/documentation.html)へ！<br>
- **`th:text="${パラメータ名}"`**<br>
`ModelAndView`に格納されたパラメータを取得してコンテンツに表示します。`<div>`や`<td>`、`<p>`タグなどの時に使用します。
- **`th:value="${パラメータ名}"`**<br>
`th:text`と同様。こちらは`<input type="text">`などで使用します。

他のタグについては登場時に都度解説していきます。
***
それでは`http://localhost:8080`にアクセスしてみましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/3a7e01c6-93d1-3993-171a-0064cbe794e6.png" width="75%">
適当に名前を入力して「送信」ボタンをクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/112a39f9-3f25-2e8b-f449-f7e6fa6848b6.png" width="75%">
入力した名前が次のページで表示できました！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/63aacf21-d5db-259a-25e1-bc666724b73f.png" width="75%">
上記が`@RequestParam`によるパラメータの受け渡しです。
画像でまとめると以下のようなイメージになります。
![flow_param.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/158f6b9f-0bd5-68aa-26f7-fe30b207393c.png)


#パラメータを受け渡そう（PathVariable編）
続いてはGET方法でのみ可能なパラメータの受け渡し方法です。
この方法では、URLに含まれている文字列をそのまま取得することができます。
（例えば`http://localhost:8080/hello/xxx`にアクセスしたとき、`xxx`をパラメータとして取得できます）

`DemoController.java`の`hello`メソッドを書き換えます。

```java:DemoController.java
@GetMapping("/hello/{username}")
public ModelAndView hello(@PathVariable String username,ModelAndView mav) {
	mav.addObject("username",username);
	mav.setViewName("/hello");
	return mav;
}
```

####`@GetMapping`
これ自体は前回やっているのですが、問題は引数の方です。
URLから取得したい部分を`{}`で囲み、後述する`@PathVariable`で呼び出す用の名前を中に入れます。

####`@PathVariable`
引数の先頭に記述。これも書き方が複数ありますが、`@RequestParam`と同じのため割愛します。

また、パラメータは複数取得可能です。
たとえば「`http://localhost:8080/hello/hatopo/24`にアクセスしたとき、`hatopo`と`24`を取得したいなあ」といった場合は以下のように記述します。

```java:記述例
@GetMapping("/hello/{username}/{age}")
public ModelAndView hello(@PathVariable String username,@PathVariable int age,ModelAndView mav) {
	// 中身は省略
	return mav;
}
```
---
それでは`http://localhost:8080/hello/xxx`にアクセスしてみましょう。
（xxxは任意の文字列を入れてください）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/087f9ad1-4554-b997-b250-c77d3f07b842.png" width="75%">
`/hello`以降のパラメータを表示できました！

<details>
<summary><font color="orange">パラメータの受け渡し感が無いな・・・と思う人へ</font></summary>
<div>完全に蛇足ではありますが、テキストフィールドの値をURLにくっ付けてページ遷移させるjavascriptを記述することでパラメータの受け渡しができます。
`index.html`の`<body>`内を以下のように書き換えます。

```html:index.html
<body>
名前：<input type="text" id="name">
<input type="submit" value="送信" onclick="send()">
<script>
function send(){
	var name = document.getElementById("name").value;
	if(name == "")name = "default_name";
	location.href = "http://localhost:8080/hello/" + name;
}
</script>
</body>
```
`http://localhost:8080/`にアクセスして名前を入れて「送信」ボタンを押すと入力値が表示できます！
</div>
</details>

以上がパラメータの受け渡しになります。続けてオブジェクトの受け渡しもやりましょう。
#オブジェクトの受け渡し
オブジェクトについて知らない人は、とりあえず今は`パラメータの入った箱（クラス）`といった理解で大丈夫です。

まず、`DemoController`と同じフォルダに`User`という名前でクラスを作成し、以下のコードを追加してください。

```java:User.java
package com.example.demo;

public class User {
	private String name;
	private int age;
}
```
続けて`getter`、`setter`と呼ばれる、javaがパラメータの取得／設定をするために必要なメソッドを追加します。
手動で書いてもOKですが、自動で追加する場合はUserクラス内の適当な場所にカーソルを置いて`ソース`>>`getterおよびsetterの生成`の順にクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/23c33272-8eca-309a-601e-a0ae6f486b97.png" width="70%">
`すべて選択`>>`生成`の順にクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/424925c1-515d-d8b9-16b5-29eb5723f966.png" width="70%">
コード全体が以下のようになればOKです。

```java:User.java
package com.example.demo;

public class User {
	private String name;
	private int age;
	// ↓自動生成によって追加されるコード
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	// ↑自動生成によって追加されるコード
}
```
※Lombokというプラグインを利用するとこのコードの記述が不要になりますが、この記事では扱いません。

続けて`index.html`を以下のように書き換えます。

```html:index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/hello" method="get" th:object="${user}">
名前：<input type="text" name="name"><br>
年齢：<input type="text" name="age"><br>
<input type="submit" value="送信">
</form>
</body>
</html>
```
- **`th:object="${オブジェクト名}"`**<br>
これを記述したタグ内にあるパラメータをまとめて１つのオブジェクト名で参照できるようにします。この例だと、`name`と`age`を`user`という名前の箱に入れます。

---
`DemoController.java`の`hello`メソッドも書き換えましょう。

```java:DemoController.java
@GetMapping("/hello")
public ModelAndView hello(@ModelAttribute User user,ModelAndView mav) {
	mav.addObject("user",user);
	mav.setViewName("/hello");
	return mav;
}
```

####`@ModelAttribute`
引数の先頭に記述。フォームから送られてきたオブジェクトを変数に格納します。
このとき、Springが裏で下のようなことをしてくれます。

```java:内部の処理
User user = new User();
user.setName(name);
user.setAge(age);
```
そのため、`User`クラスに`name`というフィールド変数が定義されていなかったり、`setAge`メソッドが定義されていなかったりすると正しく動きません。

また、このアノテーションはメソッドに書くこともできますが、使い道がだいぶ異なるためこの記事では割愛します...

---
最後に`hello.html`を以下のように書き換えましょう。

```html:hello.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div th:object="${user}">
<span th:text="*{name}"></span>さんは
<span th:text="*{age}"></span>歳です！
</div>
</body>
</html>
```

- **`th:text="*{パラメータ名}"`**<br>
`th:text="${オブジェクト名.パラメータ名}"`の省略形です。<br>
`th:object={}`を記述したタグ内においては上記のように省略して書くことができます。

---
それでは`http://localhost:8080`にアクセスしましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/500454e7-9ad7-1852-896a-f71509c1cb88.png" width="70%">
適当に名前と年齢を入力して「送信」ボタンを押すと・・・
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/a2385070-0700-8baa-1d8d-bcafe4087c6d.png" width="70%">

名前と年齢を表示できました！
##おさらい
- `@RequestParam`でパラメータの受け渡し
- `@PathVariable`でURLパラメータの取得
- `@ModelAttribute`でオブジェクトの受け渡し

今回はここまでです。お疲れ様でした。
次回からはより本格的な機能について触れていきます。