Model, View, and ModelAndView
Understand how Spring MVC passes data from a controller to a view, and how the Model, view name, and ModelAndView fit together.
Introduction
A controller method rarely just does something and returns nothing - it usually needs to hand data to a page for rendering, whether that is a list of products, a logged-in user's name, or an error message. In Spring MVC, that hand-off happens through the Model. In this lesson, you will learn how to put data into the Model, how a returned String becomes a rendered page, and how ModelAndView bundles both concerns into a single return value.
- How the Model carries data from a controller to a view.
- How a returned String is resolved to an actual template.
- How ModelAndView combines a view name and model data.
- The difference between a redirect and a forward.
The MVC Flow, Revisited
Recall the Model-View-Controller pattern: the Controller receives the request and decides what needs to happen, the Model holds the data the response will be built from, and the View is the template that renders that data into HTML (or another format). A handler method's job is to populate the Model and then say which View should render it.
| Piece | Responsibility |
|---|---|
| Controller | Receives the request, calls services, decides what data is needed |
| Model | Holds the data (a Map-like object) that the view will render |
| View | A template (Thymeleaf, JSP, etc.) that turns the Model data into HTML |
Adding Data with Model
Spring will inject a Model object into any handler method that declares it as a parameter. You add data with addAttribute(name, value), and that name becomes the variable the view template can reference.
@GetMapping("/profile")public String profile(Model model) { model.addAttribute("username", "asha92"); model.addAttribute("joinYear", 2023); return "profile"; // resolves to templates/profile.html}In a Thymeleaf template, that data is now available as ${username} and ${joinYear}. The Model is essentially a bridge - the controller fills it, the view template reads from it.
Returning a View Name
The String returned from a @Controller method (without @ResponseBody) is treated as a logical view name, not raw text sent to the browser. A ViewResolver bean turns that logical name into an actual template file, typically by adding a configured prefix and suffix.
spring.mvc.view.prefix=/WEB-INF/views/spring.mvc.view.suffix=.jspClick Run to see what this code prints.
A Spring Boot app with spring-boot-starter-thymeleaf on the classpath auto-configures a resolver that looks for templates under src/main/resources/templates/ with a .html suffix, so return "profile" resolves to templates/profile.html with no extra configuration.
Using ModelAndView
Sometimes it is convenient to set both the view name and the model data in one object rather than two separate things. ModelAndView bundles them together, and a handler method can return it directly instead of taking a Model parameter and returning a String.
@GetMapping("/dashboard")public ModelAndView dashboard() { ModelAndView mav = new ModelAndView("dashboard"); mav.addObject("visits", 128); mav.addObject("lastLogin", LocalDate.now()); return mav;}Both styles - Model plus a returned view name, or a single ModelAndView - produce the exact same result. Most modern Spring MVC code favors the Model-plus-String style because it is slightly less verbose and easier to unit test.
Redirects and Forwards
A returned view name can also start with a special prefix that changes how it is handled. redirect: tells the browser to issue a brand new GET request to a different URL (useful after a successful form POST, to avoid duplicate submissions). forward: hands the request to another handler internally without a new round trip to the browser.
@PostMapping("/books/add")public String addBook(@RequestParam String title) { bookService.save(title); return "redirect:/books/list"; // browser makes a new GET request}Returning a view name directly after a POST means refreshing the page in the browser will resubmit the form. Redirecting after a successful POST (the Post/Redirect/Get pattern) avoids that problem.
Common Mistakes
- Returning a raw string of HTML from a @Controller method expecting it to render - without @ResponseBody it is treated as a view name.
- Forgetting the redirect: prefix after a form submission, leading to duplicate form resubmissions on refresh.
- Mixing Model.addAttribute and ModelAndView.addObject in the same method without realizing they populate the same underlying data.
- Not checking that the ViewResolver prefix/suffix configuration actually matches where template files live.
- Putting large amounts of business logic inside the controller just to compute values for the Model.
Best Practices
- Keep Model attribute names consistent and descriptive so templates stay readable.
- Prefer Model + returned String over ModelAndView for simpler, more testable methods.
- Always redirect after a state-changing POST request.
- Compute data in a service layer and only push the finished result into the Model.
- Use a consistent template directory structure that matches your ViewResolver configuration.
Frequently Asked Questions
Not directly in the same method call chain - pick one approach per method. Model works with a returned String; ModelAndView carries both the data and the view name itself.
ModelMap is essentially the same concept implemented as a Map subclass with a fluent addAttribute API; Model is the interface Spring MVC injects, and in practice they behave the same for everyday use.
Model attributes are not automatically carried across a redirect. Use RedirectAttributes.addFlashAttribute() if you need to pass a one-time message (like "Book saved!") across a redirect.
Key Takeaways
- The Model carries data from the controller to the view template.
- A returned String is a logical view name resolved by a ViewResolver into an actual template.
- ModelAndView bundles the view name and model data into a single object.
- redirect: triggers a new browser request; forward: hands off internally without one.
- Always redirect after a successful POST to avoid duplicate form submissions.
Summary
Model and view names are how controllers hand finished data over to the presentation layer. Next, you will flip the direction and see how data flows the other way - from an HTML form submitted by the user, back into a Java object your controller can work with.