Model → Represents data and business logic.
View → Renders the data to the user (HTML, JSON, XML, etc.).
Controller → Handles user requests, interacts with the model, and selects the view.
Spring MVC is a request-driven web framework, built around the DispatcherServlet, which acts as the front controller.
Client sends an HTTP request → The request is received by the DispatcherServlet.
DispatcherServlet consults HandlerMapping → Finds which Controller (handler) method should process the request based on URL mapping or annotations.
Controller executes business logic → It may call a service or repository layer and prepare data for the view.
Controller returns a ModelAndView object → Contains:
Model → Data to render (attributes, objects)
View name → Logical name of the view (e.g., “home”, “userProfile”)
ViewResolver resolves the view name → Maps the logical view name to an actual view technology (e.g., JSP, Thymeleaf, FreeMarker).
View is rendered → The view template is merged with model data and returned as HTML (or another format) to the browser.
Central dispatcher for HTTP requests.
Configured in web.xml (old) or via Java config (modern Spring Boot).
Maps incoming requests to appropriate controller methods.
Example: @RequestMapping("/home") → Spring uses this mapping to direct /home requests to that controller method.
Annotated with @Controller or @RestController.
Contains handler methods (like @GetMapping, @PostMapping).
Processes requests and returns model and view info.
A container for data that needs to be rendered by the view.
Use Model, ModelMap, or ModelAndView to pass data.
Maps logical view names to actual view templates.
Common resolvers:
InternalResourceViewResolver → for JSP files.
ThymeleafViewResolver → for Thymeleaf templates.
Renders model data to the user.
Can be a JSP, Thymeleaf HTML file, JSON (for REST), etc.
@Controller: Marks a class as a controller.
@RestController: Shortcut for @Controller + @ResponseBody (used in REST APIs).
@RequestMapping: Maps requests (GET, POST, etc.) to methods.
@GetMapping, @PostMapping: Shortcut for @RequestMapping(method=GET/POST).
@PathVariable: Binds URL parameters.
@RequestParam: Binds query parameters.
@ModelAttribute: Binds form data to model objects.
@ResponseBody: Sends response data directly as JSON/XML (no view rendering).
@Controller
public class HomeController {
@Autowired
private UserService userService;
@GetMapping("/home")
public String home(Model model) {
model.addAttribute("title", "Welcome to Spring MVC!");
return "home"; // logical view name
}
@RequestMapping("/users")
public String listUsers(Model model) {
// UserService (Service layer) → UserDao (DAO layer) + User (Model layer)
List<User> users = userService.listUsers();
model.addAttribute("users", users);
return "userList"; // maps to /WEB-INF/views/userList.jsp
}
@RequestMapping("/user/{id}")
public String viewUser(@PathVariable int id, Model model) {
User user = userService.findUser(id);
model.addAttribute("user", user);
return "userDetail"; // optional
}
}
Service Layer → @Service for business logic.
Repository Layer → @Repository for data access.
/WEB-INF/views/home.jsp:
<html>
<body>
<h2>${title}</h2>
</body>
</html>
/WEB-INF/views/userList.jsp:
<html>
<head><title>User List</title></head>
<body>
<h2>All Users</h2>
<table border="1">
<tr><th>ID</th><th>Name</th><th>Email</th></tr>
<c:forEach var="u" items="${users}">
<tr>
<td>${u.id}</td>
<td><a href="user/${u.id}">${u.name}</a></td>
<td>${u.email}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
(Ensure JSTL library is added to /WEB-INF/lib/ for <c:forEach> to work.)
web.xml (the web deployment descriptor — it's part of the Servlet specification)
It configures the DispatcherServlet — and optionally the ContextLoaderListener.
Think of it as the entry point that wires Spring MVC into the servlet container (like Tomcat).
<!-- /WEB-INF/web.xml -->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- Root Application Context -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- DispatcherServlet (Front Controller) -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
servlet-context.xml (Spring MVC configuration)
Loaded by the DispatcherServlet.
Defines web-related beans: Controllers, ViewResolvers, HandlerMappings, Interceptors, etc.
<!-- /WEB-INF/spring/servlet-context.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Enable @Controller, @RequestMapping -->
<mvc:annotation-driven />
<!-- Scan controllers -->
<context:component-scan base-package="com.example.web" />
<!-- Configure views -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
It uses HTTP methods to perform CRUD operations on resources, where each resource is identified by a URI.
GET: Read → Retrieve a resource or collection
POST: Create → Create a new resource
PUT: Update → Replace an existing resource
PATCH: Update → Partially modify a resource
DELETE: Delete → Remove a resource
REST APIs exchange data typically in JSON format.
@RestController
@RequestMapping("/products")
public class ProductController {
@Autowired
private PorductService productService;
@GetMapping
public Collection<Product> getAllProducts() {
return productService.values();
}
@GetMapping("/{id}")
public Product getProduct(@PathVariable int id) {
return productService.get(id);
}
@PostMapping
public Product addProduct(@RequestBody Product product) {
productService.put(product.getId(), product);
return product;
}
@DeleteMapping("/{id}")
public String deleteProduct(@PathVariable int id) {
productService.remove(id);
return "Deleted product with ID " + id;
}
}
AbstractAnnotationConfigDispatcherServletInitializer → equivalent to: web.xml
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null; // or e.g. AppConfig.class for root context
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ WebConfig.class }; // replaces servlet-context.xml
}
@Override
protected String[] getServletMappings() {
return new String[]{ "/" }; // maps DispatcherServlet
}
}
WebMvcConfigurer (with @EnableWebMvc) → Equivalent to: servlet-context.xml
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import java.util.List;
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.example")
public class WebConfig implements WebMvcConfigurer {
// Optional: manually register Jackson message converter
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
}
Spring MVC automatically uses Jackson (via MappingJackson2HttpMessageConverter) to:
Deserialize JSON → Java object for @RequestBody
Serialize Java object → JSON for @ResponseBody
Example Request (POST)
POST /products
Content-Type: application/json
{
"id": 3,
"name": "Tablet",
"price": 500.0
}
Example Response (GET)
[
{ "id": 1, "name": "Laptop", "price": 1200.0 },
{ "id": 2, "name": "Phone", "price": 800.0 },
{ "id": 3, "name": "Tablet", "price": 500.0 }
]
Jackson can be customized to change default behaviors:
@JsonProperty("new_name") → Change JSON property names
@JsonIgnore → Ignore certain fields
@JsonFormat(pattern="yyyy-MM-dd") → Format dates
JsonSerializer / JsonDeserializer → Custom serializer/deserializer
Example:
import com.fasterxml.jackson.annotation.JsonProperty;
public class Product {
@JsonProperty("id")
private int product_id;
private String name;
@JsonProperty("price")
private double cost;
// getters/setters
}