skip to content

In Spring MVC, when a controller method returns the String "home", how does that turn into an actual HTML page? Walk through logical view names, the Model, and the ViewResolver.

level: juniorimportance: must knowfreq 70%

answer

  1. logical name != file path
  2. ViewResolver maps name -> View
  3. Model carries data, not the return value
  4. prefix + name + suffix
  5. @ResponseBody bypasses resolution

basics

~10 s

The returned String is a logical view name, not a file path. A ViewResolver maps it to a real template (e.g. "home" -> /WEB-INF/home.jsp or home.html). Data reaches the view through a Model object.

solid answer

~40 s

A controller that doesn't use @ResponseBody returns a logical view name — a short symbolic String like "home", decoupled from any physical file. After the handler runs, DispatcherServlet asks its configured ViewResolver(s) to translate that name into a View object. For example InternalResourceViewResolver with prefix "/WEB-INF/views/" and suffix ".jsp" turns "home" into "/WEB-INF/views/home.jsp"; ThymeleafViewResolver resolves "home" to templates/home.html. The controller supplies data by adding attributes to a Model (or ModelMap) parameter Spring injects; those attributes become accessible in the template. The View then renders, writing HTML to the response. This indirection lets you swap the view technology or template location without touching controller code.

code

java · 12 lines
java
@Controller
public class HomeController {

    @GetMapping("/")
    public String home(Model model) {
        model.addAttribute("greeting", "Hello, world");
        // "home" is a LOGICAL view name, not a path.
        // A ViewResolver maps it -> templates/home.html (Thymeleaf)
        //                       or -> /WEB-INF/views/home.jsp (JSP)
        return "home";
    }
}

go deeper

for a junior

Must know that the String is a logical name resolved by a ViewResolver, and that Model carries data.

for a middle

Should explain the DispatcherServlet -> ViewResolver -> View render sequence and prefix/suffix mapping.

for a senior

Should contrast view resolution with @ResponseBody and mention RequestToViewNameTranslator for void returns.

for a principal

Frames view resolution as a pluggable strategy enabling technology-agnostic controllers and multi-resolver chains.

## The problem view resolution solves A Spring MVC controller handles a request and usually needs to produce an HTML page. Rather than hard-coding a file path or writing HTML in Java, the controller returns a **logical view name** — a short symbolic String like `"home"`, `"users/list"`, or `"error"`. This name is deliberately decoupled from any physical template file. Something else — a **ViewResolver** — turns that name into a concrete page. ## The players - **`DispatcherServlet`**: the front controller. Every request goes through it. After the handler (your controller method) runs, it drives view resolution and rendering. - **Logical view name**: the `String` your method returns (when not annotated `@ResponseBody`). - **`Model` / `ModelMap` / `ModelAndView`**: a map of named attributes the controller wants to expose to the view. You add data with `model.addAttribute("user", user)`. - **`ViewResolver`**: a strategy interface, `View resolveViewName(String viewName, Locale locale)`. It maps the logical name to a `View`. - **`View`**: knows how to render — `void render(Map model, HttpServletRequest, HttpServletResponse)`. It writes the actual bytes to the response. ## The flow, step by step 1. Request arrives; `DispatcherServlet` dispatches to the matching handler method. 2. The method populates the `Model` and returns `"home"`. 3. `DispatcherServlet` loops over its ordered `ViewResolver` beans, calling `resolveViewName("home", locale)` until one returns a non-null `View`. 4. The chosen `View` (e.g. a JSP wrapped in an `InternalResourceView`, or a Thymeleaf template view) is rendered with the model attributes. 5. HTML is written to the response. ## Concrete resolver examples - **`InternalResourceViewResolver`** (JSP): configured with a `prefix` and `suffix`. `"home"` → `/WEB-INF/views/home.jsp`. - **`ThymeleafViewResolver`** (Spring Boot's default when `spring-boot-starter-thymeleaf` is present): `"home"` → `classpath:/templates/home.html`. ## How data reaches the view You don't return the data — you put it in the `Model`. Spring injects a `Model` if you declare it as a parameter: ```java @GetMapping("/") public String home(Model model) { model.addAttribute("greeting", "Hello"); return "home"; } ``` In a Thymeleaf template, `${greeting}` reads that attribute. In JSP it's a request attribute. ## Common gotchas - **Returning `void`**: if the method returns void and doesn't write the response itself, Spring derives a default view name from the request path (`RequestToViewNameTranslator`). Usually you should return the name explicitly. - **Confusing a view name with a URL**: `"home"` is not `/home`. It's a symbolic key the resolver expands. - **`@ResponseBody` / `@RestController`**: these bypass view resolution entirely — the return value is serialized to the body (JSON etc.). That's a different mechanism (message conversion). - **Wrong prefix/suffix** silently yields a 404-on-forward or a missing-template error. ## When to use Server-side rendered pages (traditional MVC apps, admin panels, email HTML). For JSON APIs you skip views and use `@ResponseBody`.

  • What happens if the controller method returns void?
    Spring uses RequestToViewNameTranslator to derive a default logical view name from the request URL (e.g. /home -> "home"). This is implicit and fragile; most teams return the name explicitly. If the method writes to the HttpServletResponse itself, no view is resolved.
  • How is returning "home" different from @RestController returning "home"?
    With @Controller (no @ResponseBody), "home" is a view name resolved to a template. With @RestController (implies @ResponseBody), the literal String "home" is written to the response body via an HttpMessageConverter — no view resolution occurs.

saying these in an interview costs you the question

  • Thinking the returned String is a URL or file path that Spring opens directly
  • Believing the controller's return value carries the model data
  • Confusing view resolution with @ResponseBody/JSON serialization

context