【Eclipse】SpringBootでHTMLのフォームを扱う

# はじめに
例えばショッピングサイトや図書館の検索システムなどから連想できる`フォーム`には2つの通信方法が存在します。`Getメソッド`と`Postメソッド`と呼ばれる通信方法の扱い方と操作方法を学習したのでアウトプットのため記事を作成しました。

## HTTPリクエストについて
`Getメソッド`と`Postメソッド`はHTTPリクエストの一種です。HTTPリクエストはURLで送信先を指定し、送信先と通信をする方法を指し、情報の開示を要求したり、こちらから情報を送信することなどができます


### Getメソッドとは
ウェブページ情報を取得する際に使用します。要求内容はURLに含まれ、パラメーターはURLの一部として公開されます。URLにフォームなどで入力した情報が表示されているため理解しやすいですが、URLには長さ制限があり、ブラウザの履歴やサーバーのログも記録されるため。機密情報が公開される可能性があるので個人情報をGetメソッドで送ることは推奨されません。ダウンロードしたい画像やファイル名などをURLに記述したい場合などに使用されます

### Postメソッドとは
フォームに入力した情報をURLに記述することなくデータを送信できるため文字数の制限がなく大量のデータを送信することが可能であり、機密性の高いデータを送信することが可能ですが、これはサーバーに大きな負荷をかける可能性があります。適切な制限や検証がないと、サービスの運用に影響を及ぼす可能性があります。

### HTMLのフォームからデータを送る方法

#### Getメソッドの場合
```html:form.html
<form action="/submit" method="GET">
  <input type="text" name="name">
  <input type="text" name="email">
  <input type="submit" value="Submit">
</form>

```

```java
//　条件：以下の値を入力した場合
// nameのinputタグに"John"と入力
// emailのinputタグに"john@example.com"と入力

// 送信されるURL
/submit?name=John&email=john@example.com
```
- action属性は送信先のURLが入ります
- name属性はコントローラで値を取得するメソッドの引数に使います

#### Postメソッドの場合
```html:form.html
<form action="/submit" method="POST">
  <input type="text" name="name">
  <input type="text" name="email">
  <input type="submit" value="Submit">
</form>

```
```java
//　条件：以下の値を入力した場合
// nameのinputタグに"John"と入力
// emailのinputタグに"john@example.com"と入力

// 送信されるURL(パラメータがURLに含まれない）
/submit

//　データはHTTPリクエストメッセージボディという専用の領域に追加されるため、
// URLに表示されない。
```


## Getパラメータの受け取り方
次の例のように末尾の`?`以降の文字列を`クエリストリング`と言い、URLに値を付与することで値を送信することができます

```java
http://example.com/item?id=10&category=shoes

// 基本構文は　パラメーター名=値　
// "&" で仕切ることで複数のパラメータを送ることができます
// Getパラメータはブラウザの履歴やサーバーのログなど記録として残ってしまうので、個人情報（パスワードなど）知られてはいけない情報には使用してはいけません
```
### 【参考】Getパラメータの文字をブラウザに出力する
GETメソッドおよびPOSTメソッドから送信された値はコントローラで受け取ります。
受け取った値はHTMLで使う変数へ代入したり、メソッドの引数に使用したり様々な役割に使うことができます

#### Getメソッドの場合

http://localhost:8080/lesson/sample?name=A&bloodType=A


```java:LessonController.java
package com.example.controller;

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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/lesson")
public class LessonController {

    @GetMapping("/sample")
    @ResponseBody
    public String sample(@RequestParam("name") String name
            , @RequestParam("bloodType") String bloodType) {
    	return "名前: " + name + "さんの血液型は " + bloodType +"です";
    }
}
```
![スクリーンショット 2023-06-26 11.17.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/dbed9c20-35a2-ba30-8aaa-c2aef6d7a8f4.png)


### 参考のコードで行っていること

#### @RequestParamアノテーション

URLの末尾に "?" 以降で指定されるキーと値のペアを取得するアノテーションです
例えば、/example?param=valueというURLの場合、"param"がクエリパラメータの名前であり、"value"がその値です。
```java:LessonController.java
public String sample(@RequestParam("name") String name, @RequestParam("bloodType") String bloodType)
```
今回は2つのクエリパラメータが含まれているので、`name`,`bloodType`という文字列型（String)を宣言した仮変数へそれぞれ代入しています

```java:LessonController.java
@ResponseBody //　returnをしたときに文字列や数字などをブラウザに出力します

return "名前: " + name + "<br>血液型: " + bloodType;
名前：nameのパラメータ　+ "さんの血液型は " + bloodTypeのパラメータ + です
```

以下のimport文が必要になりますが、Exlipseの場合、@RequestParamのコードを記述した後に上書き保存を実行すると必要なimport文が自動で追記されます
```java:LessonController.java
//　追加する
import org.springframework.web.bind.annotation.RequestParam;
```

よく似たアノテーションに`@PathVariable`というものが存在しますが、こちらは`@GetMapping("/users/{userId}")`のように'{}'で囲んだ部分の値を引数に渡すものになります

詳細はこちらに記載されています

https://qiita.com/EasyCoder/items/f3059372bb61dcfad137#%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AB%E5%BC%95%E6%95%B0%E3%82%92%E6%B8%A1%E3%81%99

## 【参考】Postパラメータの文字をブラウザに出力する

Post通信で送られたデータを扱うためには`DTO`と呼ばれる専用のクラスが必要です。DTOはセッターとゲッターを含んだメソッドでフォームから送られた複数のデータを一時的に保管するためだけに用意されるクラスです。以下はEclipseで作成する方法になります

#### HTMLのフォーム（例）
```html:SampleForm.html
<form action="/submit" method="post">
  <label for="name">名前：</label>
  <input type="text" id="name" name="name" required><br>
  
  <label for="bloodType">血液型：</label>
  <input type="text" id="bloodType" name="bloodType" required><br>
  
  <input type="submit" value="送信">
</form>
```

### DTOクラスを作成する
 DTOクラス（javaファイル）を格納するパッケージを作成します。パッケージについては公式が推奨するパスは存在しないため仕様に従うなど任意で対応が必要です。

#### パッケージの作成

プロジェクトを右クリックしたら新規でパッケージを選択します
![スクリーンショット 2023-06-26 16.19.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/8a7b2ece-39f4-2052-895d-cb4e75dec493.png)
パッケージの名前を設定します
（以下はcom.exampleのformにDTOを格納することを示しています）
![スクリーンショット 2023-06-26 16.21.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/77648f27-999b-ca41-aea2-bf8bdb700897.png)

### DTOクラスを作成する

作成したパッケージ（form)を右クリックし新しいクラスを作成します
![スクリーンショット 2023-06-26 16.32.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/3c6961b7-6113-2a52-f8c4-5bd4410ca7b4.png)

### formから送信される値を格納する変数を作成する

```java:SampleForm.java
package com.example.form;

public class SampleForm {
	private String name;  // フォームのname属性に使用した名前の変数を用意する
	private String bloodType; // フォームのname属性に使用した名前の変数を用意する

// 変数名は頭文字を小文字で作成する
		
}

```
#### DTOクラスにセッターとゲッターのメソッドを作成する

Eclipseの場合はセッターとゲッターを自動で作成する機能がある
変数の左側に`!`があれば、マークをクリックし赤枠で囲まれたコマンドを実行する

![スクリーンショット 2023-06-26 16.43.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/a38dfc5a-c895-cc3b-2145-bd72e82b78d0.png)
 DTOクラスが作成しておくと、コントローラーのメソッドで呼び出しするだけでフォームから送られたメッセージボディが格納される
```java:SampleForm.java
package com.example.form;

public class SampleForm {
	private String name; 
	private String bloodType;
	
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getBloodType() {
		return bloodType;
	}
	public void setBloodType(String bloodType) {
		this.bloodType = bloodType;
	}

	
}

```

#### コントローラーに必要なimport文
フォームの送信先であるコントローラーのメソットの引数として作成したDTOクラスを呼び出すことでマッピングが実行されるが、呼び出すためにはDTOクラスのパスが必要になりますが、他のimport文と同じく、上書き保存した時点で必要であれば自動で追記してくれます
```java:LessonController.java
// 追加が必要
import com.example.form.SampleForm;
```
DTOクラスを仮引数に定義することで、メッセージボディが代入されたDTOクラスのオブジェクトがメソッド内部に実引数として渡されます。
```java:LessonController.java
@PostMapping(パス)
public String メソッド名(DTOクラス名 変数名)
```
### @PostMappingと@GetMapping

HTTPのGETメソッドとPOSTメソッドに対応したリクエストを受け取るメソッドを定義するために使用します。

フォームの属性がPostの場合、コントローラー側の送信先のメソッドが@GetMappingだと通信エラーが発生するため注意が必要です

```java:LessonController.java
package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.example.form.SampleForm;

@Controller
@RequestMapping("/lesson")
public class LessonController {
	
	@GetMapping("/form")
    
    public String formTest() {
        return "index";
    }
    
    // Post通信を受け取る場合はPostMappingに変更が必要
    @PostMapping("/sample")
    @ResponseBody
    public String postTest(SampleForm sampleForm) {
        return "名前: " + sampleForm.getName() + "<br>血液型: " + sampleForm.getBloodType();
    }
}

```

## 実行結果について

http://localhost:8080/lesson/form
#### (送信元)
![スクリーンショット 2023-06-26 18.57.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/0b78839a-963c-854c-4864-f9f626a1af03.png)
#### (送信先)
![スクリーンショット 2023-06-26 18.56.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/843c8bc7-e069-795d-c476-3a640fcbcacc.png)

### Post通信で送られた値を変数に代入して利用する

送られた値はコントローラーのメソッドであらかじめ変数に代入することで、その後に開いたHTMLで代入された値を表示することができます。

```html:
<!DOCTYPE html>
<!--HTMLファイルの中でThymeleafの特定の構文や属性を使用できるようになります。-->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Hello Spring Boot</title>
</head>
<body>
    <form action="/lesson/sample" method="post">
  <label for="name">名前：</label>
  <input type="text" id="name" name="name" required><br>
  
  <label for="bloodType">血液型：</label>
  <input type="text" id="bloodType" name="bloodType" required><br>
  
  <input type="submit" value="送信">
</form>
</body>
</html>
```

```java:LessonController.java
package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.example.form.SampleForm;

@Controller
@RequestMapping("/lesson")
public class LessonController {
	
	@GetMapping("/form")
    
	public String formTest() {
        
        return "index";
    }

    @PostMapping("/sample")
    public String postTest(SampleForm sampleForm, Model model) {
        model.addAttribute("sampleForm", sampleForm);
        return "sample";
    }
}
```

```HTML:sample.html
<!DOCTYPE html>
<!--HTMLファイルの中でThymeleafの特定の構文や属性を使用できるようになります。-->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<p th:text="'名前: ' + ${sampleForm.name}"></p>
    <p th:text="'血液型: ' + ${sampleForm.bloodType}"></p>

</body>
</html>
```

#### 送信先のHTMLでデータを取得する
Post通信で送られたデータは作成したDTOクラスに一時保存されているので、HTMLからDTOクラスのオブジェクトにアクセスすれば、HTMLのタグにデータを出力することができます。

```html:sample.html
<p th:text="'名前: ' + ${sampleForm.name}"></p>
<p th:text="'血液型: ' + ${sampleForm.bloodType}"></p>
```
#### コントローラーで変数を作る
HTMLで変数を使用するためにはコントローラーで事前に変数を作成する必要があります。今回必要な変数はDTOクラスが代入された変数なので、メソッドの引数にはDTOクラスの名称と、変数を作るためのModel属性というものが必要です。

以下の見本には2つの引数が存在します
DTOクラスのSampleFormとそれを収める仮変数（sampleForm),
Model属性とそれを収める仮変数（model）
```java:LessonController.java
@PostMapping("/sample")
    public String postTest(SampleForm sampleForm, Model model) {
        model.addAttribute("sampleForm", sampleForm);

        // Model属性が収められたmodel
        // model.addAttribute("キー", 値);のように書くことで
        // キーと値のペアをModelに追加できます。
        // (この場合、sampleForm という変数を作った）
        // このModelのデータは、次のreturnするhtmlで表示することができます。        

        return "sample"; // samplse.htmlに移動する
    }
```


### PostにはDTO（Data Transfer Object)が必要
GetメソッドではURLにフォームに入力された値を記載して情報を送りますが、Postメソッドでは送られた情報を一度専用のクラスの変数に格納します、コントローラーはそのクラスから情報を取得することでフォームから送られた値を使用します

DTOクラスの変数（フィールド）に値を代入することでフィールドへの直接的なアクセスを制限し、データの不適切な操作を防ぐことができます。サーバ側でのメッセージボディの受信は一般的にこのDTOクラスを介して行われます。

具体的には、ユーザーがフォームに入力し、その情報がサーバに送信された場合、その情報はサーバ側でDTOに格納されます。このDTOはリクエストが処理される間に存在し、リクエストが完了した時点でその寿命を終えます。

### formの送信先について

DTOを作成する場合、フォームのaction属性に記述するURLは、次のメソッドに対してのURLとなります。DTOはデータを保持するためのオブジェクトであり、ゲッターとセッターを含んだクラスです。作成したDTOクラスをメソッドの引数に定義することで、フォームから送信されたデータはDTOクラスにバインドされます。このようにして、フォームのaction属性にはメソッドのURLを指定する必要があります。


## あとがき
Javaの基礎学習の際にセッターとゲッター専用クラスについて学習をしておいたため、 DTOクラスについてスムーズに理解をすることができました。Eclipseを使用するとセッターとゲッターは自動でコードを補完してくれるので、こういった技術はどんどんアウトプットしていこうかと考えています。