13.

ModelとModelAndViewの違い

編集
この記事の要点
  • Spring MVC の ModelModelAndView の使い分け
  • Model: コントローラメソッドの引数で受け取り、View 名は戻り値 (String) で指定
  • ModelAndView: モデルと View 名を 1 つのオブジェクトで返す
  • モダンな Spring では Model + String が標準、ModelAndView は後方互換用
  • @RestController なら両方不要(@ResponseBody でオブジェクト直接返却)

 

Model(推奨)

メソッドの引数で Model を受け取り、属性を追加。戻り値は View 名(String):

@Controller
public class UserController {

    @GetMapping("/users")
    public String list(Model model) {
        List users = userService.findAll();
        model.addAttribute("users", users);
        model.addAttribute("title", "ユーザー一覧");
        return "users/list";  // ← View 名 (例: users/list.jsp)
    }

    @GetMapping("/users/{id}")
    public String show(@PathVariable Long id, Model model) {
        User user = userService.findById(id);
        model.addAttribute("user", user);
        return "users/detail";
    }
}

JSP / Thymeleaf 側


${title}

  • ${user.name}

タイトル

  • 名前

ModelAndView

モデルと View を 1 つのオブジェクトに包んで返す:

@Controller
public class UserController {

    @GetMapping("/users")
    public ModelAndView list() {
        ModelAndView mav = new ModelAndView("users/list");
        mav.addObject("users", userService.findAll());
        mav.addObject("title", "ユーザー一覧");
        return mav;
    }

    @GetMapping("/users/{id}")
    public ModelAndView show(@PathVariable Long id) {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("users/detail");
        mav.addObject("user", userService.findById(id));
        return mav;
    }
}

比較

項目ModelModelAndView
View 名戻り値の Stringオブジェクトに含む
属性追加model.addAttribute(...)mav.addObject(...)
記述量少ない多い
条件で View 変更String を分岐setViewName(...)
Spring 推奨度推奨後方互換用

条件分岐の場合の書き方比較

// Model 版
@GetMapping("/users/{id}")
public String show(@PathVariable Long id, Model model) {
    Optional user = userService.findByIdOptional(id);
    if (user.isPresent()) {
        model.addAttribute("user", user.get());
        return "users/detail";
    } else {
        model.addAttribute("error", "User not found");
        return "errors/404";
    }
}

// ModelAndView 版
@GetMapping("/users/{id}")
public ModelAndView show(@PathVariable Long id) {
    Optional user = userService.findByIdOptional(id);
    ModelAndView mav = new ModelAndView();
    if (user.isPresent()) {
        mav.setViewName("users/detail");
        mav.addObject("user", user.get());
    } else {
        mav.setViewName("errors/404");
        mav.addObject("error", "User not found");
    }
    return mav;
}

@ModelAttribute の併用

共通のモデル属性を定義したい場合:

@Controller
public class UserController {

    // すべてのメソッドのモデルに追加される
    @ModelAttribute("currentUser")
    public User currentUser(HttpSession session) {
        return (User) session.getAttribute("user");
    }

    @ModelAttribute("appName")
    public String appName() {
        return "My App";
    }

    @GetMapping("/profile")
    public String profile(Model model) {
        // currentUser, appName はすでにモデルに追加されている
        return "profile";
    }
}

RedirectAttributes(リダイレクト時)

@PostMapping("/users")
public String create(@ModelAttribute User user, RedirectAttributes redirectAttributes) {
    userService.create(user);
    redirectAttributes.addFlashAttribute("message", "登録しました");
    return "redirect:/users";
    // → /users にリダイレクト、Flash 属性は次のリクエストで利用可能
}

@GetMapping("/users")
public String list(Model model, @ModelAttribute("message") String message) {
    // リダイレクト後の最初の表示で message が利用可能
    return "users/list";
}

@RestController なら両方不要

// View を返さず JSON を返す場合
@RestController
@RequestMapping("/api/users")
public class UserApiController {

    @GetMapping
    public List list() {
        return userService.findAll();
        // ← Jackson が自動で JSON 化
    }
}

Map で簡略化

// 簡単なケースなら Map を直接返す
@GetMapping("/users/{id}")
public String show(@PathVariable Long id, Map model) {
    model.put("user", userService.findById(id));
    return "users/detail";
}

// または Model に対して直接 put しているのと同等

使い分けのまとめ

  • 新規開発: Model + String を使う
  • 条件で View 名が大きく変わる: ModelAndView も読みやすい場合あり
  • JSON API: @RestController でオブジェクト直接返却
  • レガシーコード: ModelAndView をそのまま保守

関連記事

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. インストール(eclipseプラグイン)
  2. クイックスタート
  3. プロジェクトの作成
  4. Spring Bootプロジェクトの作成
  5. Spring Bootプロジェクトの実行
  6. Spring BootでHello World!
  7. アノテーション一覧
  8. DB接続設定からエンティティおよびリポジトリの作成、値の取得まで(JPA編)
  9. DB接続設定や値の取得(JdbcTemplate編)
  10. ビューから値をモデルに格納しコントローラーで受け取る方法
  11. コントローラーにてモデルに値を格納してビューに渡す方法
  12. テンプレートエンジン
  13. ModelとModelAndViewの違い
  14. AOPの使用方法
  15. classpath: 内部ファイルの読み込み
  16. file: 外部ファイルの読み込み
  17. CSVファイルアップロード方法(Ajax)
  18. CSVファイルダウンロード方法(Ajax)
  19. Spring Bootプロジェクトのビルドと本番環境へのデプロイ方法(内部tomcat使用)
  20. Application.propertiesの環境依存設定の分割方法
  21. JPAにおけるEntityManagerの取得方法
  22. JPAにおけるjava.sql.Connectionの取得方法
  23. エラー一覧
  24. jarの引数を受け取る方法
  25. Spring BootでGmailからメール送信
  26. 複数のDBに接続する設定(Spring Boot & JPA編)
  27. ポート番号の変更
  28. Basic認証の実装と特定のURLに限定する方法
  29. Spring SecurityのBasic認証の無効化
  30. 独自のエラーページを定義する方法
  31. プロパティファイルの値やjar実行時の引数を取得する方法