1. 実習の目標と全体フロー
今回の実習では、最も基本的なCRUDの土台となる「会員管理機能」を実装します。
- 実装する機能:会員登録・会員一覧照会・会員詳細照会
- 全体の処理フロー:
- ユーザーが会員登録ページで情報を入力して送信
- Controllerでデータを受け取って登録処理を実行
- 登録完了後、会員一覧ページへ移動(Redirect)
- 一覧から特定の会員をクリックして詳細ページを表示
2. DTO(Data Transfer Object)の作成
最初に行うのは、画面(UI)とコントローラー、あるいは各レイヤー間でデータを安全に受け渡すための専用オブジェクトである MemberDTO の作成です。
実務では、データベースの構造を持つ「Entity」を直接画面に露出させない(隠蔽する)ために、このDTOを挟むのが鉄則となっています。ここでも定型コードを自動生成してくれる Lombok ライブラリを使用します。
package com.mok.demo.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter // 各フィールドのGetterメソッドを自動生成 [cite: 259]
@Setter // 各フィールドのSetterメソッドを自動生成 [cite: 260]
@ToString // クラスの情報を文字列として出力するメソッドを自動生成 [cite: 261]
public class MemberDTO {
private Long memberId; // 会員番号 [cite: 263]
private String name; // 名前 [cite: 264]
private Integer age; // 年齢 [cite: 265]
}
3. 会員登録ページの表示(GETリクエスト)
ユーザーが最初にアクセスする会員登録画面(Form)を表示する処理です。
Controller実装
@Controller
public class MemberController {
// URL: /member/form へのアクセスを処理 [cite: 282, 283]
@GetMapping("/member/form")
public void form() {
// 返り値がvoidの場合、SpringはURLと同じパスにある「member/form.html」というView(HTML)を自動的に呼び出します [cite: 285, 293]
}
}
GETリクエストの特徴 主にデータの照会やページの移動に使用されます。URLに直接パラメータを載せてアクセスできるため、ブラウザからの直接アクセスが可能で、画面の「新たに読み込み(新規ロード)」をしても安全です。
4. 会員登録の実行とデータバインディング(POSTリクエスト)
会員登録画面で入力されたデータをサーバー(Controller)へ送信し、処理する流れです。
Controller実装
@PostMapping("/member/save")
public String save(MemberDTO memberDTO) { // 画面からのデータをオブジェクトとして受信 [cite: 313]
// 1. 受信したデータをコンソールに出力して確認 [cite: 314]
System.out.println(memberDTO);
// 出力結果: MemberDTO(memberId=null, name=홍길동, age=20) [cite: 331]
// 2. 処理完了後は、二重送信問題を防ぐために一覧画面へリダイレクト [cite: 315]
return "redirect:/member/list";
}
核心概念:データバインディング(Data Binding)
画面で名前(홍길동)と年齢(20)を入力して送信すると、Springが裏側で自動的に以下のコードを実行してくれます。
MemberDTO memberDTO = new MemberDTO(); [cite: 323]
memberDTO.setName("홍길동"); [cite: 324]
memberDTO.setAge(20); [cite: 325]
このように、リクエストパラメータの値を自動的にオブジェクトに詰め込んでくれる仕組みを データバインディング(Data Binding)と呼びます。
5. 重複リクエストを防ぐ「リダイレクト(Redirect)」
会員登録(POST処理)が完了した後の戻り値(返り値)は、必ず return "redirect:/member/list"; と記述する必要があります。
⚠️ リダイレクトをしないと発生する問題(return "member/list"; の場合)
もし単純にViewのHTMLファイル名だけを返してしまうと、ユーザーが画面上で「画面更新(F5キー)」を押したときに、直前の POSTリクエスト(会員登録)がもう一度サーバーに再送信されてしまいます。その結果、同じデータが重複して何度も登録されてしまうバグ(問題)が発生します。
🔄 リダイレクト(PRGパターン)の動き
1.ブラウザが POST /member/save を送信。
2.コントローラーが処理後、redirect:/member/list を返却。
3.命令を受けたブラウザが、今度は自動的に GET /member/list という全く新しいリクエストをサーバーに送り直す。
これにより、ユーザーがその後いくら画面更新をしても安全な「GET(一覧の照会)」が走るだけになり、重複登録を完全に防ぐことができます。
6. 会員一覧照会(Model と Thymeleaf繰り返し出力)
登録された会員たちのデータを一覧画面に表示する処理です。
Controller実装
コントローラーのデータを画面(View)へ渡すには、Model オブジェクト を引数に使用します。
@GetMapping("/member/list")
public void list(Model model) { // Modelオブジェクトを注入 [cite: 355, 356]
// 1. 会員リストデータを生成(実習ではArrayListを使用) [cite: 357, 358]
List<MemberDTO> memberList = new ArrayList<>();
// 2. 生成したデータを Model に「list」という名前で格納 [cite: 359, 360, 368]
model.addAttribute("list", memberList);
}
HTML(Thymeleafによるループ出力)
画面側(HTML)では、Modelから受け取った「list」を、Thymeleafの th:each 属性(繰り返し文)を使って1行ずつ展開します。
<tr th:each="memberDTO : ${list}">
<td th:text="${memberDTO.name}">ここに名前が入ります [cite: 373]</td>
<td>
<a th:href="@{/member/detail(memberId=${memberDTO.memberId})}">詳細</a> [cite: 380, 381]
</td>
</tr>
- 出力結果(Browser): リストに格納されていた「홍길동, 김철수, 이영희, 박민수, 최유진」といった名前が順番に出力されます 。
- 動的リンク生成:
@{/member/detail(memberId=${...})}と記述することで、ブラウザには自動的に/member/detail?memberId=1というクエリパラメータ付きのURLが生成されます。
7.会員詳細照会 (@RequestParam によるパラメータ受信)
一覧画面でクリックされた会員のIDを受け取り、その会員の詳しい情報を画面に出力する処理です。
Controller実装
URLに含まれる ?memberId=1 のようなパラメータ(URL Parameter)をピンポイントで受け取るには、@RequestParam アノテーションを使用します。
@GetMapping("/member/detail")
public void detail(@RequestParam Long memberId, Model model) { // memberIdを受け取る [cite: 386, 387, 388]
// 1. 受信したIDを確認(例:memberId = 1) [cite: 394, 395]
System.out.println("要求された会員ID: " + memberId);
// 2. 該当する会員の詳細データを生成 [cite: 396, 397]
MemberDTO memberDTO = new MemberDTO(); [cite: 398]
memberDTO.setMemberId(memberId); // 受け取ったIDをセット [cite: 399]
memberDTO.setName("홍길동"); [cite: 400]
memberDTO.setAge(20); [cite: 401]
// 3. 詳細データをModelに保存して画面に届ける [cite: 402, 403]
model.addAttribute("memberDTO", memberDTO);
}
HTML
<div>
<h3>会員詳細</h3>
<p>会員番号:<span th:text="${memberDTO.memberId}"></span></p> [cite: 406]
<p>お名前:<span th:text="${memberDTO.name}"></span></p> [cite: 407]
<p>ご年齢:<span th:text="${memberDTO.age}"></span></p> [cite: 408]
</div>
出力結果(Browser): 会員番号 : 1、名前 : 홍길동、나이 : 20 と画面に正しく表示されます。
🔄 核心:Spring Boot Web(MVC)の基本処理フロー
Spring BootにおけるWebリクエストのライフサイクルは、常に以下のシンプルな流れで綺麗に回っています。これを頭に入れておくことが開発の基本です。
1.ユーザーからのリクエスト(URL入力やForm送信)
2.Controllerが要求を受信
3.DTOの生成、データバインディングおよびビジネスロジックの処理
4.処理した結果データを Model に保存
5.View(HTML / Thymeleaf)にデータを流し込み、ブラウザに出力
まとめ
DTO : データを運ぶための専用オブジェクト(Entityの直接露出を防ぐ)。
GET : 主にデータの取得・照会・ページ移動に使用。URLにパラメータが載る。
POST : 主にデータの登録・保存に使用。パラメータはURLに露出しない。
Data Binding : 送られてきたパラメータを、Springが自動でJavaオブジェクトに格納してくれる仕組み。
Model : コントローラーのデータを画面(View)へ伝送するための運送役オブジェクト。
@RequestParam : URLの末尾に付く ?memberId=1 などのクエリパラメータの値を受信するアノテーション。
Redirect : ブラウザに対してURLの再リクエストを命令し、更新時のPOST重複送信バグを防止する手法。