Spring MVC 全面详解:原理、组件、实战与高级特性

目录

[一、Spring MVC 的核心定位与设计思想](#一、Spring MVC 的核心定位与设计思想)

[1. 什么是 MVC 设计模式?](#1. 什么是 MVC 设计模式?)

[2. Spring MVC 的核心思想:前端控制器模式](#2. Spring MVC 的核心思想:前端控制器模式)

[二、Spring MVC 的核心组件(职责与协作)](#二、Spring MVC 的核心组件(职责与协作))

[三、Spring MVC 的工作流程(核心执行链路)](#三、Spring MVC 的工作流程(核心执行链路))

[四、Spring MVC 的核心配置(注解驱动为主)](#四、Spring MVC 的核心配置(注解驱动为主))

[1. 环境准备(Maven 依赖)](#1. 环境准备(Maven 依赖))

[2. Java 核心配置类](#2. Java 核心配置类)

[(1)Web 容器初始化配置(替代 web.xml)](#(1)Web 容器初始化配置(替代 web.xml))

[(2)Spring MVC 配置类(WebConfig)](#(2)Spring MVC 配置类(WebConfig))

(3)根容器配置类(RootConfig)

五、核心注解与请求处理

[1. 控制器注解](#1. 控制器注解)

[2. 请求映射注解](#2. 请求映射注解)

示例:请求映射

[3. 请求参数绑定注解](#3. 请求参数绑定注解)

示例:参数绑定

六、数据模型与视图渲染

[1. 向视图传递数据](#1. 向视图传递数据)

[示例:Model 传递数据](#示例:Model 传递数据)

[Thymeleaf 视图渲染(user/list.html)](#Thymeleaf 视图渲染(user/list.html))

[2. RESTful 接口返回 JSON](#2. RESTful 接口返回 JSON)

[示例:返回 JSON](#示例:返回 JSON)

七、拦截器(HandlerInterceptor)

[1. 自定义拦截器](#1. 自定义拦截器)

[2. 注册拦截器(WebConfig 中配置)](#2. 注册拦截器(WebConfig 中配置))

八、异常处理

[1. 局部异常处理(@ExceptionHandler)](#1. 局部异常处理(@ExceptionHandler))

[2. 全局异常处理(@ControllerAdvice)](#2. 全局异常处理(@ControllerAdvice))

九、高级特性

[1. 跨域请求处理(CORS)](#1. 跨域请求处理(CORS))

[2. 文件上传](#2. 文件上传)

[3. 异步请求处理](#3. 异步请求处理)

[十、Spring MVC 的优势与应用场景](#十、Spring MVC 的优势与应用场景)

核心优势

应用场景

Spring MVC 是 Spring 框架的Web 模块,基于 MVC(Model-View-Controller)设计模式构建,用于快速开发灵活、松耦合的 Web 应用。它通过「前端控制器」统一处理请求,分离数据处理、页面展示和请求分发逻辑,是目前 Java 后端主流的 Web 开发框架之一。

一、Spring MVC 的核心定位与设计思想

1. 什么是 MVC 设计模式?

MVC 将应用分为三个核心角色,实现关注点分离:

  • Model(模型):封装业务数据和逻辑(如实体类、Service 层),专注数据处理;
  • View(视图):负责数据展示(如 JSP、Thymeleaf、Vue 页面),专注界面渲染;
  • Controller(控制器):接收用户请求,协调 Model 和 View(如调用 Service 获取数据,传递给 View 展示),专注请求分发。

2. Spring MVC 的核心思想:前端控制器模式

Spring MVC 通过DispatcherServlet(前端控制器) 统一接收所有请求,替代传统 MVC 中每个 Controller 独立处理请求的方式,实现「请求集中分发、组件解耦复用」。

简单说:DispatcherServlet 是整个 Spring MVC 的「中央调度器」,所有请求先经过它,再由它分发给对应的组件处理,最终返回响应。

二、Spring MVC 的核心组件(职责与协作)

Spring MVC 的核心组件围绕 DispatcherServlet 协同工作,每个组件各司其职:

三、Spring MVC 的工作流程(核心执行链路)

请求从客户端到服务器的完整处理流程,是理解 Spring MVC 的关键:

  1. 客户端发送请求 :如 http://localhost:8080/user/list,请求被 Tomcat 等 Servlet 容器接收;
  2. DispatcherServlet 接收请求:Servlet 容器将请求转发给 DispatcherServlet(配置的 URL 映射决定);
  3. HandlerMapping 匹配 Handler:DispatcherServlet 调用 HandlerMapping,根据请求 URL / 方法找到对应的 Controller 方法(Handler);
  4. HandlerAdapter 执行 Handler:DispatcherServlet 通过 HandlerAdapter 适配并执行 Handler,处理请求参数绑定、数据转换,调用 Service 层获取数据;
  5. Handler 返回 ModelAndView:Controller 方法执行完毕,返回 ModelAndView(或直接返回数据);
  6. ViewResolver 解析视图:DispatcherServlet 调用 ViewResolver,根据 ModelAndView 中的视图名称解析出实际 View;
  7. View 渲染响应:View 将 Model 数据渲染到页面(或直接返回 JSON 数据),生成响应;
  8. DispatcherServlet 返回响应:将渲染后的响应返回给客户端。

四、Spring MVC 的核心配置(注解驱动为主)

Spring MVC 支持XML 配置Java 配置,目前主流是 Java 配置(无 XML),以下是核心配置方式:

1. 环境准备(Maven 依赖)

XML 复制代码
<!-- Spring MVC 核心依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.20</version>
</dependency>
<!-- Servlet API(Tomcat 已提供,需标记为 provided) -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<!-- Thymeleaf 视图依赖(可选,替代 JSP) -->
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.12.RELEASE</version>
</dependency>

2. Java 核心配置类

(1)Web 容器初始化配置(替代 web.xml)

通过 AbstractAnnotationConfigDispatcherServletInitializer 配置 DispatcherServlet 和 Spring 容器:

java 复制代码
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

// Web 应用初始化器,替代 web.xml
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // 根容器配置类(Service、Dao 层)
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{RootConfig.class};
    }

    // Spring MVC 容器配置类(Controller、ViewResolver 等)
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    // DispatcherServlet 的 URL 映射("/" 表示处理所有请求)
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
(2)Spring MVC 配置类(WebConfig)
java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

@Configuration
@EnableWebMvc // 开启 Spring MVC 注解驱动(替代 XML 的 <mvc:annotation-driven>)
@ComponentScan("com.example.controller") // 扫描控制器包
public class WebConfig implements WebMvcConfigurer {

    // 配置 Thymeleaf 视图解析器
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine);
        resolver.setCharacterEncoding("UTF-8");
        return resolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine(ServletContextTemplateResolver templateResolver) {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver);
        return engine;
    }

    @Bean
    public ServletContextTemplateResolver templateResolver() {
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
        resolver.setPrefix("/WEB-INF/views/"); // 视图前缀(页面存放路径)
        resolver.setSuffix(".html"); // 视图后缀
        resolver.setTemplateMode("HTML5");
        resolver.setCharacterEncoding("UTF-8");
        return resolver;
    }

    // 静态资源处理(如 CSS、JS、图片)
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**") // 访问路径
                .addResourceLocations("/WEB-INF/static/"); // 实际存放路径
    }
}
(3)根容器配置类(RootConfig)
java 复制代码
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan(
    basePackages = "com.example",
    excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)
)
// 扫描 Service、Dao 层,排除 Spring MVC 相关配置
public class RootConfig {
}

五、核心注解与请求处理

Spring MVC 通过注解简化请求映射和参数处理,以下是高频注解:

1. 控制器注解

  • @Controller:标注类为 Spring MVC 控制器,处理请求并返回视图;
  • @RestController@Controller + @ResponseBody 组合,返回 JSON/XML 数据(无需视图渲染),适用于 RESTful 接口。

2. 请求映射注解

  • @RequestMapping:映射请求 URL、方法(GET/POST)、参数等,可标注在类或方法上;
  • @GetMapping@RequestMapping(method = RequestMethod.GET) 的简写;
  • @PostMapping@RequestMapping(method = RequestMethod.POST) 的简写;
  • @PutMapping/@DeleteMapping:对应 PUT/DELETE 请求,支持 RESTful 风格。
示例:请求映射
java 复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/user") // 类级映射:所有方法URL前缀为 /user
public class UserController {

    // 匹配 GET /user/list
    @GetMapping("/list")
    public String userList() {
        return "user/list"; // 返回视图名称,ViewResolver 解析为 /WEB-INF/views/user/list.html
    }

    // 匹配 POST /user/add
    @PostMapping("/add")
    public String addUser() {
        return "redirect:/user/list"; // 重定向到列表页
    }

    // RESTful:匹配 GET /user/1(路径参数)
    @GetMapping("/{id}")
    @ResponseBody // 返回 JSON 数据
    public String getUserById(@PathVariable("id") Integer id) {
        return "User ID: " + id;
    }
}

3. 请求参数绑定注解

  • @RequestParam :绑定请求参数(如 ?name=张三);
  • @PathVariable :绑定 URL 路径参数(如 /user/{id});
  • @RequestBody:绑定请求体(JSON/XML 数据),适用于 POST/PUT 请求;
  • @RequestHeader:绑定请求头信息;
  • @CookieValue:绑定 Cookie 数据;
  • @ModelAttribute:绑定请求参数到实体对象(表单提交常用)。
示例:参数绑定
java 复制代码
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
public class UserRestController {

    // 绑定请求参数:/user/query?name=张三&age=20
    @GetMapping("/query")
    public String queryUser(
        @RequestParam("name") String name,
        @RequestParam(value = "age", defaultValue = "18") Integer age
    ) {
        return "Name: " + name + ", Age: " + age;
    }

    // 绑定路径参数:/user/123
    @GetMapping("/{id}")
    public String getUser(@PathVariable("id") Long id) {
        return "User ID: " + id;
    }

    // 绑定请求体(JSON):POST /user/save,Body {"name":"李四","age":25}
    @PostMapping("/save")
    public String saveUser(@RequestBody User user) {
        return "Saved: " + user.getName() + ", " + user.getAge();
    }

    // 表单提交绑定到实体:POST /user/form,FormData name=王五&age=30
    @PostMapping("/form")
    public String formSubmit(@ModelAttribute User user) {
        return "Form: " + user.getName();
    }
}

// User 实体类
class User {
    private String name;
    private Integer age;
    // getter/setter
}

六、数据模型与视图渲染

1. 向视图传递数据

Controller 可通过以下方式将数据传递给视图:

  • Model/ModelMap:添加数据到模型,视图可直接访问;
  • ModelAndView:同时封装视图名称和模型数据;
  • @SessionAttributes:将数据存入 Session(跨请求共享)。
示例:Model 传递数据
java 复制代码
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Arrays;
import java.util.List;

@Controller
@RequestMapping("/user")
public class UserController {

    @GetMapping("/list")
    public String userList(Model model) {
        // 模拟从 Service 获取用户列表
        List<User> userList = Arrays.asList(
            new User("张三", 20),
            new User("李四", 25)
        );
        // 添加数据到模型,视图中可通过 "users" 访问
        model.addAttribute("users", userList);
        model.addAttribute("title", "用户列表");
        return "user/list"; // 返回视图名称
    }
}
Thymeleaf 视图渲染(user/list.html)
html 复制代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title th:text="${title}">用户列表</title>
</head>
<body>
    <h1 th:text="${title}">用户列表</h1>
    <table>
        <tr>
            <th>姓名</th>
            <th>年龄</th>
        </tr>
        <tr th:each="user : ${users}">
            <td th:text="${user.name}">张三</td>
            <td th:text="${user.age}">20</td>
        </tr>
    </table>
</body>
</html>

2. RESTful 接口返回 JSON

使用 @RestController@ResponseBody,Spring MVC 会自动将对象序列化为 JSON(需引入 Jackson 依赖):

XML 复制代码
<!-- Jackson 依赖(JSON 序列化) -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.5</version>
</dependency>
示例:返回 JSON
java 复制代码
@RestController
@RequestMapping("/api/user")
public class UserApiController {

    @GetMapping("/{id}")
    public User getUser(@PathVariable("id") Long id) {
        return new User("张三", 20); // 自动序列化为 JSON:{"name":"张三","age":20}
    }
}

七、拦截器(HandlerInterceptor)

拦截器用于在请求处理的前、中、后 插入自定义逻辑(如登录验证、日志记录、权限检查),实现 HandlerInterceptor 接口:

1. 自定义拦截器

java 复制代码
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor implements HandlerInterceptor {

    // 请求处理前执行(返回 true 继续,false 终止)
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 检查用户是否登录
        Object user = request.getSession().getAttribute("user");
        if (user == null) {
            // 未登录,重定向到登录页
            response.sendRedirect("/login");
            return false;
        }
        return true; // 已登录,继续处理请求
    }

    // 请求处理后、视图渲染前执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 可修改 ModelAndView 数据
    }

    // 视图渲染后执行(常用于资源清理)
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 记录请求完成日志
    }
}

2. 注册拦截器(WebConfig 中配置)

java 复制代码
@Configuration
@EnableWebMvc
@ComponentScan("com.example.controller")
public class WebConfig implements WebMvcConfigurer {

    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/user/**") // 拦截 /user 下所有请求
                .excludePathPatterns("/user/login"); // 排除登录请求
    }
}

八、异常处理

Spring MVC 提供多种异常处理方式,实现统一的异常响应:

1. 局部异常处理(@ExceptionHandler)

在 Controller 内定义,仅处理当前 Controller 的异常:

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {

    // 处理当前 Controller 的 RuntimeException
    @ExceptionHandler(RuntimeException.class)
    public String handleRuntimeException(RuntimeException e, Model model) {
        model.addAttribute("error", e.getMessage());
        return "error"; // 跳转到错误页面
    }
}

2. 全局异常处理(@ControllerAdvice)

全局生效,处理所有 Controller 的异常:

java 复制代码
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice // 全局控制器增强
public class GlobalExceptionHandler {

    // 处理所有 Exception
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception e) {
        ModelAndView mav = new ModelAndView();
        mav.addObject("error", "系统异常:" + e.getMessage());
        mav.setViewName("error"); // 错误页面
        return mav;
    }

    // 处理 REST 接口异常,返回 JSON
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public String handleIllegalArgument(IllegalArgumentException e) {
        return "{\"code\":400,\"msg\":\"" + e.getMessage() + "\"}";
    }
}

九、高级特性

1. 跨域请求处理(CORS)

通过 @CrossOrigin 或全局配置支持跨域:

java 复制代码
// 局部跨域(Controller/方法级)
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:8081") // 允许 8081 端口跨域
public class ApiController {
    // ...
}

// 全局跨域(WebConfig 中配置)
@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/api/**")
            .allowedOrigins("http://localhost:8081")
            .allowedMethods("GET", "POST")
            .allowCredentials(true);
}

2. 文件上传

配置文件上传解析器,处理 multipart 请求:

java 复制代码
// WebConfig 中配置文件上传
@Bean
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver resolver = new CommonsMultipartResolver();
    resolver.setMaxUploadSize(10 * 1024 * 1024); // 最大上传大小 10MB
    resolver.setDefaultEncoding("UTF-8");
    return resolver;
}

// Controller 处理文件上传
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
    // 保存文件
    file.transferTo(new File("D:/uploads/" + file.getOriginalFilename()));
    return "redirect:/success";
}

3. 异步请求处理

支持异步响应(如处理耗时任务),避免线程阻塞:

java 复制代码
@RestController
@RequestMapping("/async")
public class AsyncController {

    @GetMapping("/task")
    public Callable<String> asyncTask() {
        return () -> {
            // 模拟耗时任务(5秒)
            Thread.sleep(5000);
            return "异步任务完成";
        };
    }
}

十、Spring MVC 的优势与应用场景

核心优势

  1. 松耦合设计:组件职责清晰,通过注解和接口解耦,易于扩展;
  2. 强大的配置灵活性:支持注解驱动、Java 配置、XML 配置,适配不同场景;
  3. 与 Spring 生态无缝集成:可直接使用 Spring 的 IoC、AOP、事务管理等功能;
  4. 全面的功能支持:覆盖请求处理、数据绑定、视图渲染、异常处理、拦截器等;
  5. RESTful 友好:原生支持 RESTful 风格的 URL 映射和 JSON 数据交互。

应用场景

  • 传统服务器渲染的 Web 应用(JSP/Thymeleaf);
  • RESTful API 接口开发(前后端分离项目);
  • 企业级 Web 应用(如电商、OA 系统);
  • 微服务架构中的 API 网关或服务接口。
相关推荐
STARFALL00142 分钟前
spring mvc 自定义Converter 设置
java·spring·mvc
java_logo43 分钟前
Jenkins Docker 容器化部署指南
java·运维·servlet·docker·容器·jdk·jenkins
♡喜欢做梦1 小时前
MyBatis操作数据库(进阶):动态SQL
java·数据库·sql·java-ee·mybatis
lusasky1 小时前
com.itextpdf堆外内存(Off-Heap Memory)泄露
java
.豆鲨包1 小时前
【Android】深入理解Window和WindowManager
android·java
Dylan的码园1 小时前
ArrayList与顺序表
java·数据结构·链表
Boop_wu1 小时前
[Java EE] 文件操作(系统文件和字节流字符流)
java·java-ee
Aevget1 小时前
「Java EE开发指南」如何在MyEclipse中开发EJB 2 Session Bean?(二)
java·ide·java-ee·开发工具·myeclipse
带刺的坐椅1 小时前
Solon AI 开发学习11 - chat - 工具调用与定制(Tool Call)
java·ai·llm·solon