Spring MVC View
$count++; if($count == 1) { #include "../mobilemenu.php"; } if ($count == 2) { include "../sharemediasubfolder.php"; } ?>
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.