はじめに
例えばショッピングサイトや図書館の検索システムなどから連想できるフォーム
には2つの通信方法が存在します。Getメソッド
とPostメソッド
と呼ばれる通信方法の扱い方と操作方法を学習したのでアウトプットのため記事を作成しました。
HTTPリクエストについて
Getメソッド
とPostメソッド
はHTTPリクエストの一種です。HTTPリクエストはURLで送信先を指定し、送信先と通信をする方法を指し、情報の開示を要求したり、こちらから情報を送信することなどができます
Getメソッドとは
ウェブページ情報を取得する際に使用します。要求内容はURLに含まれ、パラメーターはURLの一部として公開されます。URLにフォームなどで入力した情報が表示されているため理解しやすいですが、URLには長さ制限があり、ブラウザの履歴やサーバーのログも記録されるため。機密情報が公開される可能性があるので個人情報をGetメソッドで送ることは推奨されません。ダウンロードしたい画像やファイル名などをURLに記述したい場合などに使用されます
Postメソッドとは
フォームに入力した情報をURLに記述することなくデータを送信できるため文字数の制限がなく大量のデータを送信することが可能であり、機密性の高いデータを送信することが可能ですが、これはサーバーに大きな負荷をかける可能性があります。適切な制限や検証がないと、サービスの運用に影響を及ぼす可能性があります。
HTMLのフォームからデータを送る方法
Getメソッドの場合
<form action="/submit" method="GET">
<input type="text" name="name">
<input type="text" name="email">
<input type="submit" value="Submit">
</form>
// 条件:以下の値を入力した場合
// nameのinputタグに"John"と入力
// emailのinputタグに"john@example.com"と入力
// 送信されるURL
/submit?name=John&email=john@example.com
- action属性は送信先のURLが入ります
- name属性はコントローラで値を取得するメソッドの引数に使います
Postメソッドの場合
<form action="/submit" method="POST">
<input type="text" name="name">
<input type="text" name="email">
<input type="submit" value="Submit">
</form>
// 条件:以下の値を入力した場合
// nameのinputタグに"John"と入力
// emailのinputタグに"john@example.com"と入力
// 送信されるURL(パラメータがURLに含まれない)
/submit
// データはHTTPリクエストメッセージボディという専用の領域に追加されるため、
// URLに表示されない。
Getパラメータの受け取り方
次の例のように末尾の?
以降の文字列をクエリストリング
と言い、URLに値を付与することで値を送信することができます
http://example.com/item?id=10&category=shoes
// 基本構文は パラメーター名=値
// "&" で仕切ることで複数のパラメータを送ることができます
// Getパラメータはブラウザの履歴やサーバーのログなど記録として残ってしまうので、個人情報(パスワードなど)知られてはいけない情報には使用してはいけません
【参考】Getパラメータの文字をブラウザに出力する
GETメソッドおよびPOSTメソッドから送信された値はコントローラで受け取ります。
受け取った値はHTMLで使う変数へ代入したり、メソッドの引数に使用したり様々な役割に使うことができます
Getメソッドの場合
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 +"です";
}
}
参考のコードで行っていること
@RequestParamアノテーション
URLの末尾に "?" 以降で指定されるキーと値のペアを取得するアノテーションです
例えば、/example?param=valueというURLの場合、"param"がクエリパラメータの名前であり、"value"がその値です。
public String sample(@RequestParam("name") String name, @RequestParam("bloodType") String bloodType)
今回は2つのクエリパラメータが含まれているので、name
,bloodType
という文字列型(String)を宣言した仮変数へそれぞれ代入しています
@ResponseBody // returnをしたときに文字列や数字などをブラウザに出力します
return "名前: " + name + "<br>血液型: " + bloodType;
名前:nameのパラメータ + "さんの血液型は " + bloodTypeのパラメータ + です
以下のimport文が必要になりますが、Exlipseの場合、@RequestParamのコードを記述した後に上書き保存を実行すると必要なimport文が自動で追記されます
// 追加する
import org.springframework.web.bind.annotation.RequestParam;
よく似たアノテーションに@PathVariable
というものが存在しますが、こちらは@GetMapping("/users/{userId}")
のように'{}'で囲んだ部分の値を引数に渡すものになります
詳細はこちらに記載されています
【参考】Postパラメータの文字をブラウザに出力する
Post通信で送られたデータを扱うためにはDTO
と呼ばれる専用のクラスが必要です。DTOはセッターとゲッターを含んだメソッドでフォームから送られた複数のデータを一時的に保管するためだけに用意されるクラスです。以下はEclipseで作成する方法になります
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ファイル)を格納するパッケージを作成します。パッケージについては公式が推奨するパスは存在しないため仕様に従うなど任意で対応が必要です。
パッケージの作成
プロジェクトを右クリックしたら新規でパッケージを選択します
パッケージの名前を設定します
(以下はcom.exampleのformにDTOを格納することを示しています)
DTOクラスを作成する
作成したパッケージ(form)を右クリックし新しいクラスを作成します
formから送信される値を格納する変数を作成する
package com.example.form;
public class SampleForm {
private String name; // フォームのname属性に使用した名前の変数を用意する
private String bloodType; // フォームのname属性に使用した名前の変数を用意する
// 変数名は頭文字を小文字で作成する
}
DTOクラスにセッターとゲッターのメソッドを作成する
Eclipseの場合はセッターとゲッターを自動で作成する機能がある
変数の左側に!
があれば、マークをクリックし赤枠で囲まれたコマンドを実行する
DTOクラスが作成しておくと、コントローラーのメソッドで呼び出しするだけでフォームから送られたメッセージボディが格納される
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文と同じく、上書き保存した時点で必要であれば自動で追記してくれます
// 追加が必要
import com.example.form.SampleForm;
DTOクラスを仮引数に定義することで、メッセージボディが代入されたDTOクラスのオブジェクトがメソッド内部に実引数として渡されます。
@PostMapping(パス)
public String メソッド名(DTOクラス名 変数名)
@PostMappingと@GetMapping
HTTPのGETメソッドとPOSTメソッドに対応したリクエストを受け取るメソッドを定義するために使用します。
フォームの属性がPostの場合、コントローラー側の送信先のメソッドが@GetMappingだと通信エラーが発生するため注意が必要です
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();
}
}
実行結果について
(送信元)
(送信先)
Post通信で送られた値を変数に代入して利用する
送られた値はコントローラーのメソッドであらかじめ変数に代入することで、その後に開いた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>
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";
}
}
<!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のタグにデータを出力することができます。
<p th:text="'名前: ' + ${sampleForm.name}"></p>
<p th:text="'血液型: ' + ${sampleForm.bloodType}"></p>
コントローラーで変数を作る
HTMLで変数を使用するためにはコントローラーで事前に変数を作成する必要があります。今回必要な変数はDTOクラスが代入された変数なので、メソッドの引数にはDTOクラスの名称と、変数を作るためのModel属性というものが必要です。
以下の見本には2つの引数が存在します
DTOクラスのSampleFormとそれを収める仮変数(sampleForm),
Model属性とそれを収める仮変数(model)
@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を使用するとセッターとゲッターは自動でコードを補完してくれるので、こういった技術はどんどんアウトプットしていこうかと考えています。