0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【SpringBoot】実践クローン:ControllerとDTOによる会員管理機能の実実装

0
Posted at

1. 実習の目標と全体フロー

今回の実習では、最も基本的なCRUDの土台となる「会員管理機能」を実装します。

  • 実装する機能:会員登録・会員一覧照会・会員詳細照会
  • 全体の処理フロー:
  1. ユーザーが会員登録ページで情報を入力して送信
  2. Controllerでデータを受け取って登録処理を実行
  3. 登録完了後、会員一覧ページへ移動(Redirect)
  4. 一覧から特定の会員をクリックして詳細ページを表示

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重複送信バグを防止する手法。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?