5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[速習] Spring 第4回 ~実践的なWebアプリケーション構築~ (Spring MVCのコントローラ設計/フォームバリデーション実装)

Last updated at Posted at 2025-06-10

image.png

前回までの記事では、Springのコア技術であるDI(依存性注入)とAOP(アスペクト指向)について解説しました。今回は、これらの知識を活かしながらSpring MVCを使った実践的なWebアプリケーション構築について、コントローラ設計、リクエスト・レスポンス処理、フォームバリデーションを中心に解説します。

Spring MVCアーキテクチャの全体像

Spring MVCは、Springフレームワークが提供するWebアプリケーション構築のためのMVC1アーキテクチャです。リクエスト処理の責務を明確に分離することで、保守性と再利用性に優れたアプリケーションを実現します。

各コンポーネントの役割

  • DispatcherServlet: すべてのHTTPリクエストを受け付けるフロントコントローラ
  • @Controller: プレゼンテーション層でリクエストを処理(@RestControllerはREST API向け)
  • @Service: ビジネスロジックを実装(トランザクション境界はここに配置することが多い)
  • @Repository: データアクセス層を担当(Spring Data JPAなどと連携)
  • View: レスポンスの生成(Thymeleaf、JSPなど)

この階層構造により、各レイヤーの責務が明確になり、変更の影響を局所化できます。

コントローラの実装とリクエストマッピング

Spring MVCでは、@Controllerアノテーションでコントローラクラスを定義し、各種マッピングアノテーションでURLとメソッドを紐付けます。

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.example.demo.form.ProductForm;
import com.example.demo.service.ProductService;

import jakarta.validation.Valid;
import java.util.List;

@Controller
@RequestMapping("/products")
public class ProductController {

    private final ProductService productService;

    // Spring Boot 3.x以降は単一コンストラクタの場合@Autowired省略可能
    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    // 商品一覧表示
    @GetMapping
    public String list(Model model) {
        List<Product> products = productService.findAll();
        model.addAttribute("products", products);
        return "product/list"; // templates/product/list.html
    }

    // 商品登録フォーム表示
    @GetMapping("/add")
    public String showAddForm(Model model) {
        model.addAttribute("productForm", new ProductForm());
        return "product/add";
    }

    // 商品登録処理
    @PostMapping("/add")
    public String addProduct(
            @Validated @ModelAttribute ProductForm form,
            BindingResult result,  // 必ず検証対象の直後に配置
            RedirectAttributes redirectAttributes) {
        
        if (result.hasErrors()) {
            return "product/add"; // エラー時は入力画面へ
        }
        
        Long productId = productService.register(form);
        redirectAttributes.addFlashAttribute("message", 
            "商品を登録しました(ID: " + productId + ")");
        
        return "redirect:/products";
    }
}

ポイント解説

  1. BindingResultの位置: Spring MVCの仕様上、BindingResultは必ず検証対象パラメータの直後に配置する必要があります
  2. RedirectAttributes: リダイレクト時にフラッシュスコープでメッセージを渡せます
  3. Model2: コントローラからビューへデータを渡すためのコンテナ

Bean Validationによるフォームバリデーション

Spring BootではBean Validation(JSR-380)が自動構成され、アノテーションベースのバリデーションが使えます。

package com.example.demo.form;

import jakarta.validation.constraints.*;

public class ProductForm {
    
    @NotBlank(message = "商品名は必須です")
    @Size(max = 100, message = "商品名は100文字以内で入力してください")
    private String name;
    
    @NotNull(message = "価格は必須です")
    @PositiveOrZero(message = "価格は0以上の値を入力してください")
    @Max(value = 1000000, message = "価格は100万円以下で入力してください")
    private Integer price;
    
    @Size(max = 500, message = "説明は500文字以内で入力してください")
    private String description;
    
    // getter/setter
}

@ValidatedとValid の使い分け

  • @Valid: 標準的なBean Validation(jakarta.validation)
  • @Validated: Springの拡張アノテーション(グループバリデーション3をサポート)

グループバリデーションを使わない場合は@Validでも十分ですが、将来の拡張性を考慮して@Validatedを使うことを推奨します。

Thymeleafテンプレートとの連携

ビュー層では、Thymeleafを使ってサーバーサイドの値を表示します。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>商品登録</title>
</head>
<body>
    <h1>商品登録</h1>
    
    <form th:action="@{/products/add}" th:object="${productForm}" method="post">
        <!-- CSRF対策トークン(Spring Securityで自動生成) -->
        <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
        
        <div>
            <label for="name">商品名:</label>
            <input type="text" id="name" th:field="*{name}" />
            <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" 
                  style="color: red;">エラーメッセージ</span>
        </div>
        
        <div>
            <label for="price">価格:</label>
            <input type="number" id="price" th:field="*{price}" />
            <span th:if="${#fields.hasErrors('price')}" th:errors="*{price}" 
                  style="color: red;">エラーメッセージ</span>
        </div>
        
        <button type="submit">登録</button>
    </form>
</body>
</html>

エラーメッセージのカスタマイズ

Spring Bootではsrc/main/resources/messages.propertiesにメッセージを定義すると、自動的にMessageSourceが構成されます。

# messages.properties
product.name.required=商品名を入力してください
product.price.invalid=正しい価格を入力してください

# messages_en.properties(英語版)
product.name.required=Product name is required
product.price.invalid=Please enter a valid price

例外ハンドリングとAOPの活用

@ControllerAdviceを使うと、横断的な例外処理を実装できます。これもAOPの考え方を活用した仕組みです。

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(DataAccessException.class)
    public String handleDatabaseError(DataAccessException e, Model model) {
        model.addAttribute("error", "データベースエラーが発生しました");
        return "error/database";
    }
    
    @ExceptionHandler(BusinessException.class)
    public String handleBusinessError(BusinessException e, Model model) {
        model.addAttribute("error", e.getMessage());
        return "error/business";
    }
}

DI/AOPを活用したアーキテクチャ

Spring MVCのレイヤー構造では、DIによる疎結合とAOPによる横断的関心事の分離が実現されています。

※上図は、DIによる依存関係とAOPによる横断的処理の適用を表しています。Mermaidが描画されない環境では、コントローラ→サービス→リポジトリの依存関係と、それらに対するトランザクション・ロギングのアスペクト適用をイメージしてください。

まとめ

今回は、Spring MVCを使った実践的なWebアプリケーション構築について解説しました。

本記事で学んだこと

  • Spring MVCのアーキテクチャとコンポーネントの役割
  • コントローラの実装とリクエストマッピング
  • Bean Validationによる入力値検証
  • Thymeleafテンプレートとの連携
  • 例外ハンドリングとAOPの活用

これらの要素が、前回学んだDI/AOPと密接に連携して動作することで、Spring MVCの強力かつ柔軟なWebアプリケーション開発が可能になります。

次回は「Springのデータアクセス(Spring Data JPA)とトランザクション管理」について、より実践的な内容を解説する予定です。

この記事が、Spring MVCを使った実践的なWebアプリケーション開発の第一歩となることを願っています!


参考文献


  1. MVC(Model-View-Controller) - アプリケーションを「モデル(データ・ビジネスロジック)」「ビュー(表示)」「コントローラ(制御)」の3つに分離する設計パターン。責務の分離により保守性が向上する。

  2. Model - Spring MVCでコントローラからビューへデータを渡すためのコンテナ。addAttributeメソッドで値をセットする。

  3. グループバリデーション - 登録時と更新時で異なる検証ルールを適用するなど、状況に応じてバリデーションを切り替える仕組み。@Validatedでグループを指定できる。

5
4
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
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?