概述
- 定义:用于构建 Web 应用程序的框架,MVC 代表 Model-View-Controller 模式
- 核心思想:将 "请求处理"、"视图渲染"、"数据模型" 分离,使得职责清晰、代码可维护
- MVC
- Model:也就是开发中的 Mapper 层,表示对模型和数据库的操作,也可以带上 Service,因为 Service 是业务逻辑
- View:是 HTML 部分,在前后端分离的架构中属于 VUE 和 React 的职责(传统架构中的 Spring 也可以负责 View,比如 JSP/Thymeleaf)
- Controller:也就是开发中的 Controller 层,负责接收 View 的请求并进行响应
- 核心功能
- 请求处理:接收和处理 HTTP 请求,支持各种 HTTP 方法(GET、POST、PUT、DELETE 等)
- URL 映射:通过注解(如 @RequestMapping)将 URL 映射到对应的处理方法
- 数据绑定:自动将请求参数绑定到 Java 对象,支持复杂的数据类型转换
- 视图解析:支持多种视图技术(JSP、Thymeleaf 等),也支持 RESTful API 的 JSON 响应
- 验证框架:集成了强大的数据验证功能,支持 JSR-303 标准
- 文件上传:内置的文件上传支持,可以轻松处理多文件上传
- 异常处理:提供统一的异常处理机制,支持自定义错误页面和异常处理器
- 组成部分
DispatcherServlet
:核心的中央处理器,负责协调整个请求的处理流程(接收客户端的请求,将请求分发给适当的组件处理,并最终返回响应)Handler
:请求处理器(Controller),执行实际的业务逻辑处理,并生成处理结果(通常会返回一个 ModelAndView 或在前后端分离项目中返回 JSON 数据)HandlerMapping
:处理器映射器,根据请求的 URL 匹配并查找能够处理该请求的 Handler,同时将相关的拦截器信息一并封装HandlerAdapter
:处理器适配器,在 DispatcherServlet 和 Handler 之间提供一个适配层,使得不同类型的 Handler 都能被统一处理ViewResolver
:视图解析器,在前后端不分离的项目中根据 Handler 返回的逻辑视图名解析为实际的视图(如 JSP 模板或 Thymeleaf),并将视图渲染为最终的 HTML 页面返回给客户端
工作流程
- 发送请求:浏览器或客户端发送 HTTP 请求到服务器
- 拦截请求 :所有的请求首先会被前端控制器
DispatcherServlet
(用于协调整个请求的处理流程)拦截 - 映射请求 :
DispatcherServlet
根据请求 URL,使用HandlerMapping
找到处理这个请求的合适的控制器(Controller) - 处理请求:Controller 开始处理业务逻辑(通常会调用服务层和数据访问层)
- 返回 ModelAndView :Controller 返回一个
ModelAndView
对象,这个对象包含了视图名和模型数据 - 解析视图 :
DispatcherServlet
会使用ViewResolver
来解析ModelAndView
中的视图名,找到合适的视图(通常是一个 JSP、Thymeleaf 模板等) - 渲染视图 :视图解析后,
DispatcherServlet
会将模型数据传递给视图进行渲染,最终生成 HTML 页面 - 返回响应给客户端 :渲染后的视图会被返回给客户端,显示给用户
前后端模式
前后端分离
-
目标:后端专注于数据处理和业务逻辑,通过 RESTful API 提供 JSON 类型的数据服务,而前端负责页面渲染和用户交互
-
优点:使得前后端能够独立开发、测试和部署,提高了开发效率和系统的可维护性
-
特点:只需要返回 JSON 格式的数据,不再需要 ViewResolver / View 等组件,这部分交给前端进行处理
-
组成部分
- Controller:接收前端请求,处理请求,响应数据
- Service:用于处理具体业务逻辑的接口类,由 ServiceImpl 类实现 Service 接口中的方法
- Dao:Data Access Object,提供一个数据库操作的途径,包含用于访问数据库的方法,使得应用程序不直接与数据库交互
-
工作流程
-
Controller 中注入 Service 依赖,Service 中注入 Mapper 依赖
-
Controller 接收客户端请求,调用 Service 的逻辑方法
-
ServiceImpl 实现 Service 接口,调用 Mapper 的数据库访问功能
-
Mapper 返回数据或执行结果给 ServiceImpl 实现类
-
ServiceImpl 返回数据或执行结果给 Controller
-
Controller 返回 Response 给客户端
controller 发出请求,service提供实现逻辑,dao 层提供数据支持
-
-
流程图
Client DispatcherServlet HandlerMapping HandlerAdapter Handler Service Mapper 1. 发送HTTP请求 2. 查找处理器 3. 返回Handler 4. 适配处理器 5. 执行处理 6. 处理业务逻辑 7. 数据库操作 8. 返回数据 9. 返回处理结果 10. 返回数据 11. 转换为JSON 12. 返回JSON响应 Client DispatcherServlet HandlerMapping HandlerAdapter Handler Service Mapper
前后端不分离
-
定义:Controller + Thymeleaf 引擎(视图层)
-
流程图
Client DispatcherServlet HandlerMapping HandlerAdapter Handler ViewResolver View 1. 发送 HTTP 请求 2. 查找处理器 3. 返回Handler 4. 适配处理器 5. 执行处理 6. 返回ModelAndView 7. 返回ModelAndView 8. 解析视图 9. 返回View 10. 渲染视图 11. 返回渲染结果 12. 返回HTTP响应 Client DispatcherServlet HandlerMapping HandlerAdapter Handler ViewResolver View
MVC 配置
默认配置
- 默认的静态资源路径:默认从 resources 下的
static
、public
、META_INF/static
、resources
文件夹中获取静态资源,并且可以直接访问 - 数据类型转换和格式化:通过自动注册 Converter / GenericConverter / Formatter 组件
- 返回 JSON 数据类型:通过 HttpMessageConverters 转换器,并通过 @ResponseBody 注解声明
- 自动实现 消息处理、数据绑定、类型转换、数据校验 等功能(通过 ConfigurableWebBindingInitializer )
- 包含 ContentNegotiatingViewResolver 和 BeanNameViewResolver 组件,方便视图解析(不常用,因为现在已经前后端分离了)
- 提供国际化和错误消息处理
手动配置
- 完全手动配置:自定义一个 @Configuration 类,继承 WebMvcConfigurer 接口并标注 @EnableWebMvc 禁用默认配置
- ⭐ 部分手动配置:最佳实践,写一个 @Configuration 配置类,实现 WebMvcConfigurer 接口,不标注 @EnableWebMvc 注解(因为是部分自定义,其他使用默认配置)
- 工作原理
- WebMvcAutoConfiguration 是一个自动配置类,里面有一个 EnableWebMvcConfiguration 继承了 DelegatingWebMvcConfiguration
- DelegatingWebMvcConfiguration 利用 DI 将容器中所有 WebMvcConfigurer 注入到容器中,实现了所有的 WebMvc 配置
- 用户用配置类继承 WebMvcConfigurer 会将这个 WebMvcConfigurer 注册到容器中
- Spring 调用 DelegatingWebMvcConfiguration 的方法配置底层规则时,DelegatingWebMvcConfiguration 负责加载了用户自定义的规则部分
WebMvcConfigurer
-
定义:一个用于自定义 Spring MVC 配置的接口
-
功能:根据需求来扩展或定制 Spring MVC 的默认配置,比如添加拦截器、格式化器、消息转换器等
-
使用方法:实现 WebMvcConfigurer 接口并覆盖其中的方法
-
调用时间:当 Spring Boot 启动时,Spring 容器会自动检测并调用所有实现了
WebMvcConfigurer
接口的配置类,并执行其定义的方法- 注意:由于这是 Spring Boot 的初始化配置,所以 JRebel 也无法及时更新这部分已经加载到 IOC 容器中的配置,需要重新启动项目才能生效
-
常见实现场景
- 添加拦截器:通过实现
addInterceptors(InterceptorRegistry registry)
来注册自定义拦截器。 - 配置视图解析器:通过
addViewControllers(ViewControllerRegistry registry)
增加简单的视图映射。 - 扩展消息转换器:使用
configureMessageConverters(List<HttpMessageConverter> converters)
来添加或修改消息转换器。 - 配置路径匹配策略:通过
configurePathMatch(PathMatchConfigurer configurer)
来设置路径匹配规则。
- 添加拦截器:通过实现
-
注意:如果使用 Spring Boot,Spring 容器会自动检测实现了 WebMvcConfigurer 的配置类,无需额外配置。
-
常用方法
返回值类型 命令 功能 void addInterceptors(InterceptorRegistry registry)
注册拦截器到 Spring 容器 void addViewControllers(ViewControllerRegistry registry)
添加视图控制器 void configureContentNegotiation(ContentNegotiationConfigurer configurer)
配置内容协商策略 void configureMessageConverters(List<HttpMessageConverter<?>> converters)
配置消息转换器 void configurePathMatch(PathMatchConfigurer configurer)
配置路径匹配选项
WebMvcAutoConfiguration
- 定义:WebMvcAutoConfiguration 是 Spring Boot 的自动配置类,用于配置 Spring MVC 的默认行为
- 功能
- 提供 Spring MVC 的默认配置,包括视图解析器、静态资源处理、消息转换器等
- 支持自动配置 ViewResolver、静态资源映射、welcome 页面等
- 配置默认的 HttpMessageConverters,用于处理 HTTP 请求和响应的转换
- 生效条件
- @ConditionalOnWebApplication:当前应用是一个 Web 应用(WebApplication)
- @ConditionalOnClass:类路径下存在 Servlet API 和 Spring MVC
- @ConditionalOnMissingBean:没有使用 @EnableWebMvc 注解(使用该注解会完全接管 Spring MVC 的配置)
- 主要组件配置
ContentNegotiatingViewResolver
:处理视图解析BeanNameViewResolver
:通过 Bean 名称解析视图InternalResourceViewResolver
:处理 JSP 视图解析MultipartResolver
:处理文件上传
- 静态资源配置
- 默认的静态资源位置:/static、/public、/resources、/META-INF/resources
- 静态资源缓存策略
- 欢迎页配置:index.html
核心组件
DispatcherServlet
- 定义:中央调度 Servlet,是 Servlet 的老大、Spring MVC 的核心组件,充当中央调度器的角色,用于协调整个请求处理流程
- 功能:负责接收 HTTP 请求,将请求分发给适当的处理器(Handler),并最终返回响应。它提供了共享算法用于处理请求,并将实际工作委托给其他组件完成。
- 配置方式
- 方式一:在 Web 应用中通过 Spring 配置文件(如 XML)进行初始化和声明
- 方式二:Java Config(如实现 WebApplicationInitializer 接口)进行初始化和声明
- 继承树:HttpServlet → HttpServletBean → FrameworkServlet → DispatcherServlet → GenericServlet
HandlerAdapter
-
定义:
-
功能:
-
核心方法
javapublic interface HandlerAdapter { // 判断是否支持这个 handler(如是否是注解控制器) boolean supports(Object handler); // 真正执行业务逻辑,返回 ModelAndView ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; // 用于缓存优化,一般用不到(服务端资源是否过期) long getLastModified(HttpServletRequest request, Object handler); }
-
常见实现类
实现类 适配的处理器类型 用途说明 RequestMappingHandlerAdapter
注解控制器(如 @Controller
,@RestController
)⭐ 最常用,现代 Spring 应用中主力 SimpleControllerHandlerAdapter
实现了 Controller
接口的类早期老项目可能使用 HttpRequestHandlerAdapter
实现 HttpRequestHandler
的类类似于 Servlet,处理低层请求 HandlerFunctionAdapter
Spring 5 的函数式风格 Handler WebFlux 或函数式注册 Handler 用
HandlerMapping
- 定义
- HandlerMapping:Spring MVC 中的一个接口,它定义了如何将 HTTP 请求 映射到对应的 controller 方法的规则
- ⭐ RequestMappingHandlerMapping :HandlerMapping 接口最重要的实现类,是默认启用的 HanderMapping,负责处理 @RequestMapping 相关的 Mapping
- RequestMappingHandlerMapping 功能
- 负责扫描和注册带有 @RequestMapping(以及其派生注解如 @GetMapping、@PostMapping 等)注解的处理器方法(Handler Methods)
- 负责将 @RequestMapping 注解的处理器方法与对应的请求路径(URL)映射起来,形成一个"请求映射表"
- 负责将请求 URL 映射到 @RequestMapping 注解的处理器方法
核心注解
注解 | 作用 |
---|---|
@ResponseBody |
表示方法的返回值直接写入 HTTP 响应体,而不是解析为视图 |
@RestController |
是 @Controller + @ResponseBody 的组合注解,类中所有方法默认都加上了 @ResponseBody |
@ResponseStatus |
指定 HTTP 响应状态码,不影响数据转换,但会影响响应状态 |
@ModelAttribute |
表示返回值会添加到模型(Model)中,用于视图渲染 |
@PathVariable / @RequestParam 等 |
用于方法参数绑定,与返回值无关 |
| 💡
注意:如果不加 @RestController
也不加 @ResponseBody
,则返回的对象会被当做试图名称进行解析,不会触发**HttpMessageConverter
**
自定义参数解析过程
-
整体流程:"Adapter 找方法 → Invocable 找参数 → Resolver 解析值 → Binder 绑进对象"
bashDispatcherServlet#doDispatch ↓ RequestMappingHandlerAdapter#invokeHandlerMethod ↓ InvocableHandlerMethod#invokeForRequest ↓ HandlerMethodArgumentResolverComposite#getMethodArgumentValues ↓ ┌────────────── 内置 + 自定义 Resolver 逐个尝试 ──────────────┐ RequestParamResolver │ PathVariableResolver │ RequestBodyResolver │ ... │YourCustomResolver ↓ └──────────────────────────────────────────────────────┘ WebDataBinder.bind() ← 针对 @ModelAttribute 或普通 JavaBean ↓ Controller 方法真正执行
-
关键节点
步骤 关键类 / 方法 作用 源码片段 & 提示 ① 适配 RequestMappingHandlerAdapter#invokeHandlerMethod
创建 ServletWebRequest
、InvocableHandlerMethod
invocable.invokeAndHandle(webRequest, mavContainer);
(tty4.dev)② 解析参数 InvocableHandlerMethod#getMethodArgumentValues
遍历方法形参,委派给 参数解析器链 this.argumentResolvers.getArgumentResolver(parameter)
(github.com)③ 参数解析器 HandlerMethodArgumentResolverComposite
内置 + 自定义 Resolver 顺序匹配 自定义的 Resolver 会插在 内置之后 ( setCustomArgumentResolvers
)(docs.spring.io)④ 数据绑定 WebDataBinder.bind()
→BeanWrapperImpl.setPropertyValues()
把表单字段 / Query‑String 值 copy 到 JavaBean 字段,期间走 ConversionService 详见 ServletModelAttributeMethodProcessor
调createAttribute()
后调用binder.bind()
(baeldung.com)⑤ 类型转换 DefaultFormattingConversionService
String → Integer/Date/Enum
等全局共享,可通过 @InitBinder
或注册Converter
/Formatter
拓展
示例
-
场景:前端发送 JSON 请求,后端接收并转为 Java 对象
-
请求内容
- 请求头:
Content-Type: application/json
- 请求体:
{"name": "张三", "age": 25}
- 请求头:
-
Controller 方法
java@PostMapping("/user") public ResponseEntity<String> createUser(@RequestBody User user) { // ... }
-
工作流程
@RequestBody
:让 Spring 知道需要把请求体转为 Java 对象。Content-Type: application/json
:让 Spring 从HttpMessageConverter
列表中找到支持 JSON 的转换器(比如 MappingJackson2HttpMessageConverter)。- Spring 使用该转换器将 JSON 字符串转成
User
对象。