一、什么是SpringMVC
SpringMVC(Spring Model-View-Controller)是Spring框架的一个模块,用于开发Web应用程序。它是一个基于请求驱动的框架,负责处理用户的请求,分发请求到合适的处理方法,并返回响应。SpringMVC遵循了经典的MVC设计模式,将Web应用分为三个部分:
- Model(模型):主要是业务逻辑部分,用来保存数据或与数据库进行交互。
- View(视图):用于显示数据,通常是JSP、Thymeleaf、FreeMarker等模板。
- Controller(控制器):接受用户的请求,处理业务逻辑,调用模型层,返回数据,最终选择合适的视图进行展示。
SpringMVC的主要作用是实现请求的分发与业务逻辑的处理,同时与Spring框架其他部分(如Spring的依赖注入、事务管理等)配合,提供完整的Web开发解决方案。
二、SpringMVC执行原理流程
要深入理解SpringMVC的执行原理,我们需要从请求的接收到响应的过程来分析。SpringMVC的工作流程大致可以分为以下几个步骤:
客户端请求(浏览器发起请求):
- 用户在浏览器中输入URL或点击某个链接发起HTTP请求。
前端控制器(DispatcherServlet):
- 所有的请求都会首先到达SpringMVC的核心组件——
DispatcherServlet
(前端控制器)。 DispatcherServlet
负责请求的分发和协调,它是整个SpringMVC的入口。
- 所有的请求都会首先到达SpringMVC的核心组件——
请求映射(HandlerMapping):
DispatcherServlet
会根据请求的URL,使用HandlerMapping
来确定哪个控制器(Controller)的方法来处理这个请求。HandlerMapping
会查找符合请求的映射关系,通常通过注解(如@RequestMapping
)来定义。
- 控制器适配器
HandlerAdapter
经过适配调用具体的处理器(Handler/Controller)
控制器处理请求(Controller):
- 找到对应的
Controller
后,DispatcherServlet
会调用该控制器的处理方法(比如@RequestMapping
标注的方法)。 - 控制器方法处理业务逻辑、数据查询等,并将结果返回给
DispatcherServlet
。
- 找到对应的
视图解析(ViewResolver):
- 控制器方法的返回值一般是一个视图名称,SpringMVC会通过
ViewResolver
来解析出具体的视图(比如JSP文件、Thymeleaf模板等)。 ViewResolver
根据视图名称和配置的前后缀规则(如/WEB-INF/jsp/
+viewName
+.jsp
)找到对应的视图资源。
- 控制器方法的返回值一般是一个视图名称,SpringMVC会通过
返回响应(返回给客户端):
- 解析得到的视图会将数据渲染成HTML(或其他格式),然后响应给客户端(浏览器)。
整个流程的关键是DispatcherServlet
,它起到了“调度”和“分发”的作用,其他组件(如HandlerMapping
、HandlerAdapter
、ViewResolver
等)各司其职,确保请求的高效处理。
三、SpringMVC工作流程图(自上而下阅读)
分阶段详细流程
阶段 1:请求到达 DispatcherServlet
- 入口类:
DispatcherServlet#doDispatch()
(核心调度方法) 关键操作:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) { // 1. 获取HandlerExecutionChain(包含拦截器链) HandlerExecutionChain mappedHandler = getHandler(request); // 2. 获取HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 3. 执行拦截器preHandle if (!mappedHandler.applyPreHandle(request, response)) return; // 4. 实际调用Controller方法 ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler()); // 5. 处理视图渲染 applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(request, response, mv); processDispatchResult(request, response, mappedHandler, mv, dispatchException); }
阶段 2:路由匹配(HandlerMapping)
核心实现类:
RequestMappingHandlerMapping
:处理@RequestMapping
注解BeanNameUrlHandlerMapping
:基于Bean名称映射
匹配逻辑:
// RequestMappingHandlerMapping#getHandlerInternal() protected HandlerMethod getHandlerInternal(HttpServletRequest request) { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); this.mappingRegistry.getMappingsByUrl(lookupPath); // 从注册表查询 }
阶段 3:参数绑定(HandlerAdapter)
- 核心类:
RequestMappingHandlerAdapter
关键步骤:
- 参数解析:通过
HandlerMethodArgumentResolver
解析@RequestParam
、@RequestBody
等 - 数据转换:使用
HttpMessageConverter
处理JSON/XML等格式 - 验证:执行
@Valid
参数校验
- 参数解析:通过
阶段 4:拦截器(Interceptor)执行
执行顺序:
preHandle → Controller → postHandle → 视图渲染 → afterCompletion
源码入口:
// HandlerExecutionChain#applyPreHandle() boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) { for (int i = 0; i < this.interceptorList.size(); i++) { if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } } }
阶段 5:视图渲染
核心流程:
- 视图解析:
ViewResolver#resolveViewName()
→ 生成View
对象 - 模型填充:
View#render()
合并Model数据 - 输出响应:通过
HttpServletResponse
写入HTML/JSON
- 视图解析:
关键设计模式
模式 | 应用场景 | 实现类示例 |
---|---|---|
前端控制器 | 统一请求入口 | DispatcherServlet |
策略模式 | 可插拔的组件 | HandlerMapping 实现类 |
适配器模式 | 兼容多种Controller类型 | HandlerAdapter |
责任链模式 | 拦截器链执行 | HandlerInterceptor |
与Spring Boot的集成差异
自动配置类:
WebMvcAutoConfiguration
默认注册的组件:
@Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { // 默认配置JSON转换器、参数解析器等 }
定制扩展:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()); } }
常见问题排查技巧
404 错误:
- 检查
@Controller
是否被扫描到 - 确认URL路径与
@RequestMapping
匹配
- 检查
参数绑定失败:
- 调试
HandlerMethodArgumentResolver
实现类
- 调试
视图解析失败:
- 检查
ViewResolver
配置和模板路径
- 检查
拦截器不生效:
- 确认
Interceptor
注册顺序和excludePathPatterns
- 确认
四、SpringMVC的入门案例
以下是一个结合 Spring Boot 和 Spring MVC 的简单入门案例,包含详细步骤和代码,帮助你快速搭建一个基础的 Web 应用。
1. 环境准备
- JDK 17+
- Maven 3.6+
- IDE(推荐 IntelliJ IDEA 或 VS Code)
2. 创建 Spring Boot 项目
使用 Spring Initializr 快速生成项目:
- 访问 start.spring.io
选择以下配置:
- Project: Maven
- Language: Java
- Spring Boot: 3.2.x
- Packaging: Jar
Dependencies:
Spring Web
(集成 Spring MVC)Thymeleaf
(可选,用于模板引擎)
- 点击 Generate 下载项目,解压后用 IDE 打开。
3. 项目结构
src/
├── main/
│ ├── java/
│ │ └── com/example/demo/
│ │ ├── DemoApplication.java # Spring Boot 启动类
│ │ └── controller/
│ │ └── HelloController.java # MVC 控制器
│ └── resources/
│ ├── static/ # 静态资源(CSS/JS)
│ ├── templates/ # 视图模板(HTML)
│ └── application.properties # 配置文件
4. 编写代码
(1) 控制器类 `HelloController.java`
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
// 返回 HTML 视图(需要 Thymeleaf)
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("message", "Hello, Spring MVC!");
return "hello"; // 对应 templates/hello.html
}
// 返回 JSON 数据
@GetMapping("/api/hello")
@ResponseBody
public String apiHello() {
return "{\"message\": \"Hello, Spring Boot!\"}";
}
}
(2) 视图模板 templates/hello.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Spring MVC Demo</title>
</head>
<body>
<h1 th:text="${message}">Default Message</h1>
</body>
</html>
(3) 配置文件 application.properties
# 设置端口
server.port=8080
# Thymeleaf 配置(关闭缓存,开发时使用)
spring.thymeleaf.cache=false
5. 运行应用
- 打开启动类
DemoApplication.java
,运行main
方法。 访问以下 URL:
- HTML 页面: http://localhost:8080/hello
- JSON 接口: http://localhost:8080/api/hello
6. 关键注解说明
注解 | 说明 |
---|---|
@Controller | 声明为 MVC 控制器,处理 HTTP 请求 |
@GetMapping | 映射 HTTP GET 请求到指定方法 |
@ResponseBody | 直接返回数据(JSON/文本),不经过视图解析 |
Model | 向视图传递数据的容器 |
7. 扩展功能
(1) 静态资源访问
将 CSS/JS 文件放在 src/main/resources/static/
下,直接通过 URL 访问:
例如:http://localhost:8080/css/style.css
(2) 使用 RESTful API
@RestController // = @Controller + @ResponseBody
@RequestMapping("/api")
public class UserController {
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return new User(id, "Alice");
}
}
(3) 连接数据库
添加依赖 Spring Data JPA
+ H2 Database
,编写 Repository
和 Entity
类。
8. 常见问题
- 404 错误:检查 URL 路径和控制器方法是否匹配。
- Thymeleaf 模板不生效:确保
templates/
目录正确,且依赖已添加。 - 端口冲突:在
application.properties
中修改server.port
。
通过这个案例,你可以快速掌握 Spring Boot + Spring MVC 的基础用法,后续介绍springmvc的全局异常处理!