MTI TEK
Spring Framework
|
Spring MVC
Spring MVC with Thymeleaf
Spring MVC — Overview
- Spring MVC is a Servlet-based web framework built around the Front Controller pattern. A single
DispatcherServlet receives all incoming HTTP requests and delegates to @Controller beans via HandlerMapping. The controller processes the request, optionally populates a Model, and returns a logical view name. The DispatcherServlet hands that name to a ViewResolver to produce the HTTP response.
- The three roles in the pattern map directly to Spring constructs:
- Model — a
Map of attributes populated by the controller and passed to the view; Spring MVC exposes it as Model, ModelMap, or ModelAndView.
- View — a template resolved by a
ViewResolver (Thymeleaf, JSP, etc.) that renders the model into an HTTP response body.
- Controller — a Spring bean annotated with
@Controller whose handler methods are mapped to HTTP request paths via @RequestMapping and its specializations.
@RequestMapping at the class level sets a base path prefix for all handler methods in that controller. Its method-level specializations — @GetMapping, @PostMapping, @PutMapping, @PatchMapping, @DeleteMapping — each constrain the mapping to a specific HTTP verb. A handler method returning a String from a @Controller (not @RestController) is treated as a logical view name, not a response body.
Dependencies
spring-boot-starter-webmvc brings in Spring MVC, an embedded Tomcat, and Jackson. It is distinct from spring-boot-starter-web — both pull the same transitive graph in current Boot releases, but spring-boot-starter-webmvc is the more explicit, Servlet-MVC-specific artifact.
spring-boot-starter-thymeleaf autoconfigures a ThymeleafViewResolver that resolves logical view names to classpath:/templates/<name>.html. This resolver takes precedence over any InternalResourceViewResolver.
- The test scope introduces three separate starters:
spring-boot-starter-test (JUnit 5, AssertJ, Mockito), spring-boot-starter-webmvc-test (MockMvc infrastructure), and spring-boot-starter-thymeleaf-test (Thymeleaf rendering support in slice tests).
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
@Controller and View Name Resolution
@Controller is a specialization of @Component — it is picked up by component scanning and registered as a Spring bean. Unlike @RestController, it does not apply @ResponseBody to handler methods, so return values are treated as logical view names and passed to the configured ViewResolver.
@GetMapping("/") maps HTTP GET on the root path. The method returns the logical view name "home" — Thymeleaf's ThymeleafViewResolver resolves it to /src/main/resources/templates/home.html by applying the default prefix classpath:/templates/ and suffix .html.
- The commented-out alternative (
return "redirect:/home.html") would serve the file from /src/main/resources/static/ via Spring's static resource handler. A redirect adds an extra HTTP round-trip and bypasses Thymeleaf processing entirely; note the comment in the code warns the test needs to be updated for that path.
@ModelAttribute-annotated methods in a @Controller are invoked before every handler method in that controller. They can add attributes to the Model that are then available in the view. Attributes placed in the Model are copied into servlet request attributes before the view renders.
@SessionAttributes declared on a controller class promotes specific model attributes into the HTTP session, keeping them available across multiple requests to the same controller — useful for multi-step form flows.
@Controller
public class HomeController {
@GetMapping("/")
public String home() {
// returns logical view name "home"
// resolved to /src/main/resources/templates/home.html
return "home";
}
}
Static Resources vs. Thymeleaf Templates
- This project contains two files named
home.html in different locations:
src/main/resources/templates/home.html — rendered by Thymeleaf, reached by returning the logical name "home" from a @Controller method.
src/main/resources/static/home.html — served verbatim as a static resource at the URL /home.html, bypassing any controller or template engine.
- When Thymeleaf is on the classpath,
ThymeleafViewResolver takes priority. A controller returning "home" always hits templates/home.html, not static/home.html. The static file is only reachable by direct URL or via redirect:/home.html.
- The commented-out properties in
application.properties show an alternative: configuring a plain InternalResourceViewResolver backed by the static directory. This approach works only when Thymeleaf is absent or the resolver order is explicitly adjusted — with Thymeleaf on the classpath, setting spring.mvc.view.prefix and spring.mvc.view.suffix alone is insufficient to override it.
# With Thymeleaf autoconfiguration active, these are ignored unless ThymeleafViewResolver precedence is explicitly lowered:
#spring.mvc.view.prefix=classpath:/static/
#spring.mvc.view.suffix=.html
@WebMvcTest Slice
@WebMvcTest(HomeController.class) is a test slice: it bootstraps only the MVC layer (controllers, filters, WebMvcConfigurers, HandlerMethodArgumentResolvers) and not the full application context. No @Service or @Repository beans are loaded unless explicitly mocked. Contrast with @SpringBootTest, which loads the full context — a heavier setup appropriate for integration tests.
- The import path is
org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest — note the boot.webmvc.test package, which is specific to the spring-boot-starter-webmvc-test artifact introduced in Spring Boot 4. Do not confuse with the older org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest from Boot 3.
MockMvc is injected via @Autowired — it is auto-configured by the slice. No explicit MockMvcBuilders.standaloneSetup() or @AutoConfigureMockMvc annotation is needed when using @WebMvcTest.
- The test verifies three things in a single chained call: HTTP status 200, the logical view name returned by the controller, and a substring match on the rendered response body. The
view().name("home") assertion catches controller-level bugs independently of template rendering.
content().string(containsString(...)) asserts on the rendered HTML output after Thymeleaf processing — not just the raw template file. The spring-boot-starter-thymeleaf-test dependency enables full template rendering inside the @WebMvcTest slice; without it, Thymeleaf view resolution would fail in the slice context.
@WebMvcTest(HomeController.class)
public class HomeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testHomePage() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("home"))
.andExpect(content().string(containsString("Welcome to MTITEK Spring MVC.")));
}
}