Spring MVC View

Introduction

The View turns your model data into a final HTTP response: HTML, JSON, PDF, CSV—anything. This page explains how Spring picks a view, common resolvers (JSP, Thymeleaf, Mustache), and how to configure them.

1 · Big Picture

Controller  ──►  returns "home"
                ▼
        ViewResolver (maps "home" → /WEB-INF/views/home.jsp)
                ▼
      View (JSP / Thymeleaf / etc.)  +  Model Map
                ▼
         Rendered HTML to Client

• The controller only returns a logical name.
• A ViewResolver chooses a concrete view implementation.
• The chosen view engine merges the model map into a template.

2 · Configuring a JSP ViewResolver

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public InternalResourceViewResolver jsp() {
        InternalResourceViewResolver vr = new InternalResourceViewResolver();
        vr.setPrefix("/WEB-INF/views/");   // folder
        vr.setSuffix(".jsp");              // file extension
        return vr;
    }
}

InternalResourceViewResolver forwards to a servlet-container resource (JSP).
• Logical view "home"/WEB-INF/views/home.jsp.
• Keep JSP files under /WEB-INF so they’re not fetchable directly via URL.

3 · Thymeleaf Setup (Modern Choice)

<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf-spring6</artifactId>
  <version>3.2.0.RELEASE</version>
</dependency>
@Bean
public SpringResourceTemplateResolver thymeleafResolver() {
    var r = new SpringResourceTemplateResolver();
    r.setPrefix("classpath:/templates/");  // src/main/resources/templates/
    r.setSuffix(".html");
    r.setTemplateMode(TemplateMode.HTML);
    return r;
}

@Bean
public SpringTemplateEngine thymeleafEngine(ITemplateResolver resolver) {
    var engine = new SpringTemplateEngine();
    engine.setTemplateResolver(resolver);
    return engine;
}

@Bean
public ThymeleafViewResolver thymeleafViewResolver(SpringTemplateEngine engine){
    var vr = new ThymeleafViewResolver();
    vr.setTemplateEngine(engine);
    vr.setOrder(1);           // win over JSP if both present
    return vr;
}

• Thymeleaf parses plain HTML5, so designers can open templates in a browser without a server.
• Expressions use {{ ${message} }} or th:text="${message}".
• Spring Boot autoconfigures all this for you—just add the dependency.

4 · Mustache / FreeMarker in Two Lines

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-mustache</artifactId>
</dependency>

Add the starter → drop *.mustache in src/main/resources/templates/.
Spring Boot wires a MustacheViewResolver automatically.

5 · Returning JSON Without a View

@RestController
class Api {

    @GetMapping("/api/clock")
    public Map<String, Object> time() {
        return Map.of("serverTime", ZonedDateTime.now());
    }
}

@RestController bypasses view resolution → body goes straight to the wire.
• Jackson converts the Map to JSON.

6 · Multiple ViewResolvers & Order

resolver1.setOrder(0);   // Thymeleaf
resolver2.setOrder(1);   // JSP fallback

• Spring asks resolvers in ascending order: first one that can handle the view wins.
• Useful to prefer Thymeleaf but keep legacy JSPs running.

7 · Model Access in Templates

<h2>Welcome, ${user}!</h2>
<!-- Thymeleaf -->
<h2 th:text="'Welcome, ' + ${user} + '!'>placeholder</h2>

• Keys added in the controller (model.addAttribute("user", "...")) are exposed to the EL/OGNL of the template engine.
• Collections can be iterated, e.g. <tr th:each="p : ${products}">…</tr>.

8 · Static Resources vs. Views

• Files under src/main/resources/static/ are served as-is (/css/app.css).
• Files under templates/ or /WEB-INF are views—they require controller resolution.
• Keep React/Angular bundles in static/ if you mix server-side and SPA.

9 · Best Practices

• Put view technology behind an interface (ViewResolver) so you can swap engines later.
• Use one resolver order (Thymeleaf > JSP) to avoid ambiguous mapping.
• Minify CSS/JS via Maven/Gradle plugins; views shouldn’t inline huge scripts.
• Externalize layout (header/footer) with Thymeleaf <th:replace="layout :: footer"> or JSP includes.
• For REST-only services, skip view engines and stick to @RestController responses.

Previous: MVC Controller | Next: @SpringBootApplication for MVC

<
>