-
Add Required Dependencies Include core Spring MVC and dependent JAR files in your project's build path:
spring-webmvc,spring-core,spring-context,spring-beans,spring-expression, andcommons-logging. -
Configure
web.xmlAdd the DispatcherServlet configuration toWEB-INF/web.xml:
<!-- Configure Spring MVC DispatcherServlet and request mapping -->
<servlet>
<servlet-name>app-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc-servlet.xml</param-value>
</init-param>
<!-- Load servlet on application startup for faster initial requests -->
<!-- <load-on-startup>1</load-on-startup> -->
</servlet>
<servlet-mapping>
<servlet-name>app-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
- Create Spring MVC Configuration File
Create
spring-mvc-servlet.xmlinsrc/main/resources:
<?xml version="1.0" encoding="UTF-8"?>
<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-5.3.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc-5.3.xsd">
<!-- Scan for controller components in the specified base package -->
<context:component-scan base-package="com.example.springmvc.controller" />
<!-- Enable default servlet handling for static resources -->
<mvc:default-servlet-handler />
<!-- Enable annotation-driven MVC configuration -->
<mvc:annotation-driven />
<!-- Configure internal resource view resolver for JSP views -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="viewResolver">
<!-- View file prefix -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- View file suffix -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
- Create View Files
Create a
jspdirectory underWEB-INF, then addhello.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
- Create MVC Controller
Create
HelloMvcController.javaincom.example.springmvc.controller:
package com.example.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/mvc")
public class HelloMvcController {
@RequestMapping("/hello")
public String sayHello() {
return "hello";
}
}
- Test the Application
Start your servlet container, then access
http://localhost:8080/your-project-name/mvc/helloto view the Hello World page.
Configuration Breakdown
- DispatcherServlet: The front controller defined in
web.xml, which intercepts matching requests and routes them to the appropriate controller. This is the first step in setting up Spring MVC. - InternalResourceViewResolver: Resolves logical view names to actual JSP files using the configured prefix and suffix.
- Core Annotations:
@Controller: Registers the class as a Spring-managed bean@RequestMapping: Maps HTTP requests to controller methods
Common Spring MVC Annotations
@Controller: Registers a class as a Spring controller bean@RequestMapping: Maps specific URL requests to controller methods@RequestBody: Reads the HTTP request body, parses it withHttpMessageConverter, and binds it to method parameters@ResponseBody: Converts the method return value to the specified response format (e.g., JSON) usingHttpMessageConverter@ModelAttribute: Populates model data before method execution, or binds request parameters to method parameters@RequestParam: Binds HTTP query parameters to controller method parameters@PathVariable: Binds URL path variables to controller method parameters@ExceptionHandler: Handles exceptions within a single controller@ControllerAdvice: Defines global exception handling, cross-cutting configuration for all controllers
Automatic Parameter Matching
Map request parameters directly to controller method parameters by matching parameter names:
@RequestMapping("/person")
public String handlePersonAuto(String username, double userAge) {
System.out.println(username + " " + userAge);
return "hello";
}
Automatic Data Binding
Bind request parameters to a custom model object automatically.
- Create the
Personmodel class incom.example.springmvc.model:
package com.example.springmvc.model;
public class Person {
private String username;
private int userAge;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getUserAge() {
return userAge;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
}
- Add the controller method:
@RequestMapping("/person1")
public String handlePersonBinding(Person person) {
System.out.println(person.getUsername() + " " + person.getUserAge());
return "hello";
}
Handle Date Parameters with @InitBinder
Convert string request parameters to Date objects using a custom binder:
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.ServletRequestDataBinder;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.propertyeditors.CustomDateEditor;
@RequestMapping("/date")
public String handleDate(Date date) {
System.out.println(date);
return "hello";
}
@InitBinder
public void initDateBinder(ServletRequestDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
Pass Data to Frontend
Add data to the model map to expose it to the view:
import java.util.Map;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/show")
public String passPersonData(Map<String, Object> model) {
Person person = new Person();
person.setUsername("jayjay");
person.setUserAge(20);
model.put("person", person);
return "show";
}
Access the person attribute in the JSP view via the request scope.
Ajax Request Handling
Create controller methods to handle AJAX calls, and use jQuery on the frontend:
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/mvc")
public class AjaxController {
@RequestMapping("/getPerson")
public void getPerson(String username, HttpServletResponse response) throws Exception {
PrintWriter writer = response.getWriter();
writer.write("Hello, " + username);
writer.flush();
writer.close();
}
@RequestMapping("/name")
public String showNamePage() {
return "name";
}
}
Frontend jQuery code:
$(function(){
$("#btn").click(function(){
$.post("mvc/getPerson", {username:$("#nameInput").val()}, function(data){
alert(data);
});
});
});
Redirect Requests
Use the redirect: prefix to perform a redirect:
@RequestMapping("/redirect")
public String handleRedirect() {
return "redirect:/mvc/hello";
}
File Upload
- Add the required Apache Commons FileUpload and IO JARs to your project.
- Configure the multipart resolver in
spring-mvc-servlet.xml:
<!-- Multipart file upload configuration -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600" />
</bean>
- Create the upload controller method:
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String handleFileUpload(HttpServletRequest request) throws Exception {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
MultipartFile uploadFile = multiRequest.getFile("uploadFile");
String originalFileName = uploadFile.getOriginalFilename();
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf('.'));
String newFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + fileExtension;
String uploadPath = request.getSession().getServletContext().getRealPath("/") + "upload/";
File targetFile = new File(uploadPath + newFileName);
if (!targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
uploadFile.transferTo(targetFile);
return "hello";
}
- Frontend form:
<form action="mvc/upload" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFile"><br>
<input type="submit" value="Upload File">
</form>
Explicit Parameter Binding with @RequestParam
Bind and validate request parameters explicitly:
package com.example.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/test")
public class ParamController {
@RequestMapping("/param")
public String handleParam(@RequestParam("userId") Integer userId,
@RequestParam("username") String username) {
System.out.println(userId + " " + username);
return "/hello";
}
}
RESTful API with Spring MVC
- Create a REST controller:
package com.example.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/rest")
public class UserRestController {
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
public String getUser(@PathVariable("userId") Integer userId) {
System.out.println("GET request for user: " + userId);
return "/hello";
}
@RequestMapping(value = "/user/{userId}", method = RequestMethod.POST)
public String createUser(@PathVariable("userId") Integer userId) {
System.out.println("POST request for user: " + userId);
return "/hello";
}
@RequestMapping(value = "/user/{userId}", method = RequestMethod.PUT)
public String updateUser(@PathVariable("userId") Integer userId) {
System.out.println("PUT request for user: " + userId);
return "/hello";
}
@RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE)
public String deleteUser(@PathVariable("userId") Integer userId) {
System.out.println("DELETE request for user: " + userId);
return "/hello";
}
}
- Enable HTTP method conversion for forms:
Add the
HiddenHttpMethodFiltertoweb.xml:
<!-- Convert POST requests to PUT/DELETE for RESTful APIs -->
<filter>
<filter-name>hiddenMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- Frontend forms for REST requests:
<!-- PUT Request -->
<form action="rest/user/1" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="Submit PUT Request">
</form>
<!-- POST Request -->
<form action="rest/user/1" method="post">
<input type="submit" value="Submit POST Request">
</form>
<!-- GET Request -->
<form action="rest/user/1" method="get">
<input type="submit" value="Submit GET Request">
</form>
<!-- DELETE Request -->
<form action="rest/user/1" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="Submit DELETE Request">
</form>
Return JSON Responses
- Add Jackson JSON processing dependencies to your project.
- Create a JSON controller:
package com.example.springmvc.controller;
import java.util.Date;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.springmvc.model.User;
@Controller
@RequestMapping("/json")
public class JsonController {
@ResponseBody
@RequestMapping("/user")
public User getUser() {
User user = new User();
user.setId(1);
user.setUsername("jayjay");
user.setBirthDate(new Date());
return user;
}
}
Exception Handling
- Local Exception Handling (per controller):
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@ExceptionHandler
public ModelAndView handleLocalException(Exception ex) {
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
System.out.println("Local exception handler triggered");
return mv;
}
@RequestMapping("/error")
public String triggerError() {
int divideByZero = 5 / 0;
return "hello";
}
- Global Exception Handling with
@ControllerAdvice:
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler
public ModelAndView handleGlobalException(Exception ex) {
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
System.out.println("Global exception handler triggered");
return mv;
}
}
- Global Exception Handling with
SimpleMappingExceptionResolver: Add this configuration tospring-mvc-servlet.xml:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
</bean>
The error view is your custom error page.
Custom Interceptor
- Create a custom interceptor class:
package com.example.springmvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class CustomInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Interceptor: afterCompletion");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor: postHandle");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Interceptor: preHandle");
return true;
}
}
- Register the interceptor in
spring-mvc-servlet.xml:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/mvc/**" />
<bean class="com.example.springmvc.interceptor.CustomInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
- Interceptor Execution Flow:
preHandle→ Controller Execution →postHandle→afterCompletion.
Form Validation and Internationaliaztion
-
Add Hibernate Validator and related dependencies to your project.
-
Create a
Usermodel with validation annotations:
package com.example.springmvc.model;
import java.util.Date;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.Past;
public class User {
private int id;
@NotEmpty(message = "Username cannot be empty")
private String username;
@Past
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
}
- Create a JSP form using Spring form tags:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Add User</title>
</head>
<body>
<form:form action="form/add" method="post" modelAttribute="user">
ID: <form:input path="id"/> <form:errors path="id"/><br>
Username: <form:input path="username"/> <form:errors path="username"/><br>
Birth Date: <form:input path="birthDate"/> <form:errors path="birthDate"/>
<input type="submit" value="Submit">
</form:form>
</body>
</html>
- Create the form controller:
package com.example.springmvc.controller;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.example.springmvc.model.User;
import java.util.Map;
@Controller
@RequestMapping("/form")
public class FormController {
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addUser(@Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "addUser";
}
return "showUser";
}
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String showAddForm(Map<String, Object> model) {
model.put("user", new User());
return "addUser";
}
}
- Customize Validation Messages
Create
validation-messages.propertiesinsrc/main/resources:
NotEmpty.user.username=Username cannot be empty
Past.user.birthDate=Birth date must be a past date
DateTimeFormat.user.birthDate=Invalid date format, please use yyyy-MM-dd
typeMismatch.user.id=Invalid ID format
Register the message source in spring-mvc-servlet.xml:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="validation-messages" />
</bean>
- Internationalization Create locale-specific property files:
messages_zh_CN.properties:
username=账号
password=密码
messages.properties:
username=Username
password=Password
Create a locale test JSP:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Internationalization Test</title>
</head>
<body>
<fmt:message key="username"/>
<br>
<fmt:message key="password"/>
</body>
</html>
Register the view controller in spring-mvc-servlet.xml:
<mvc:view-controller path="/locale" view-name="locale"/>
Access the page at http://localhost:8080/your-project-name/locale and switch browser language to see translated text.
Integrate Spring IOC and Spring MVC
-
Create a new package
com.example.springmvc.integratefor integration demo. -
Create the
Usermodel class (same as the validation model above). -
Create the
UserServiceclass:
package com.example.springmvc.integrate.service;
import org.springframework.stereotype.Component;
import com.example.springmvc.integrate.model.User;
@Component
public class UserService {
public UserService() {
System.out.println("UserService constructor initialized");
}
public void saveUser(User user) {
System.out.println("Saved user: " + user);
}
}
- Create the integration controller:
package com.example.springmvc.integrate.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.springmvc.integrate.model.User;
import com.example.springmvc.integrate.service.UserService;
@Controller
@RequestMapping("/integrate")
public class IntegrateController {
@Autowired
private UserService userService;
@RequestMapping("/user")
public String saveUser(@RequestBody User user) {
System.out.println(user);
userService.saveUser(user);
return "hello";
}
}
- Create Spring Core Configuration File
Create
applicationContext.xmlinsrc/main/resources:
<?xml version="1.0" encoding="UTF-8"?>
<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"
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-5.3.xsd">
<!-- Scan for service and component beans, exclude controllers -->
<context:component-scan base-package="com.example.springmvc.integrate">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
</beans>
- Configure Spring Context Loader in
web.xml:
<!-- Configure Spring application context loader -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
- Adjust Spring MVC Component Scan
Update
spring-mvc-servlet.xmlto only scan controller components:
<context:component-scan base-package="com.example.springmvc.integrate">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
Spring MVC Execution Flow
- Client sends a request to the DispatcherServlet
- DispatcherServlet queries HandlerMapping instances to find the appropriate controller
- DispatcherServlet forwards the request to the identified controller
- Controller processes the request and returns a ModelAndView
- DispatcherServlet resolves the view using ViewResolver instances
- The view renders the response and returns it to the client
Spring MVC vs Struts2
- Development Style: Spring MVC is method-based, mapping URLs to specific controller methods. Each method generates a single handler, with method parameters destroyed after execution. Struts2 is class-based, using member variables to handle request parameters, requiring multiple instances.
- Scope: Spring MVC uses singleton controllers by default, improving performance. Struts2 uses prototype (non-singleton) scope due to its parameter handling design.
- Performance: Spring MVC generally has better performance than Struts2, especially when avoiding Struts2-specific tags and using JSTL instead.