本专题导航
| 篇 | 主题 |
|---|---|
| 上一篇 | AOP 与事务 |
| 本篇 | Spring MVC |
| 延伸 | Spring Boot Web、运维与测试 |
背景与动机
IoC 管 Bean,AOP 管横切逻辑;到了 Web 层,还要解决:HTTP 请求怎么找到对应 Java 方法、参数怎么绑定、结果怎么变成 JSON 或页面。Spring MVC 就是 Spring 体系里的 Web 层框架,基于 Servlet,核心是 DispatcherServlet 统一调度。
搞懂 MVC 流程,才能理解 Boot 里 @RestController 为什么能直接返回 JSON,以及 Filter、Interceptor、全局异常和 Controller 谁先谁后。
核心原理拆解
1. Spring MVC 是什么
基于 Servlet 规范的 Web 层框架(不是 Servlet 替代品),在 Servlet 容器(Tomcat、Jetty 等)之上工作:
| 职责 | 说明 |
|---|---|
| 路由 | URL → Controller 方法 |
| 参数绑定 | Query、Path、Header、Body → 方法参数 |
| 调用链 | Controller → Service → DAO/Mapper |
| 响应 | 视图(JSP/Thymeleaf)或 JSON/XML(REST) |
传统 Servlet 要手写 doGet/doPost、自己解析参数、自己写 JSON;MVC 用注解声明映射,由框架完成大部分样板代码。
2. 日常开发三层:Controller → Service → Mapper
| 层 | 职责 | 常见注解 | 不该做的事 |
|---|---|---|---|
| Controller | 接 HTTP、参数校验、组装返回 | @RestController、@GetMapping | 复杂业务、直接写 SQL |
| Service | 业务逻辑、事务边界 | @Service、@Transactional | 解析 HTTP 细节 |
| Mapper / DAO | 持久化访问 | @Mapper + MyBatis XML | 业务规则、事务 |
@RestController@RequestMapping("/api/orders")public class OrderController { private final OrderService orderService;
public OrderController(OrderService orderService) { this.orderService = orderService; }
@PostMapping public OrderVO create(@RequestBody @Valid CreateOrderRequest req) { return orderService.create(req); }}
@Servicepublic class OrderService { @Transactional public OrderVO create(CreateOrderRequest req) { // 业务 + 调 Mapper }}各层 Bean 由容器注入(推荐构造器注入)。
→ 注入 IoC 篇 · 事务 AOP 篇 · MyBatis Mapper 与 XML
分层原则:Controller 薄、Service 厚;事务标在 Service 的 public 方法上,不要标在 Controller。
3. 核心组件
| 组件 | 作用 |
|---|---|
| DispatcherServlet | 前端控制器,所有请求入口,协调下面各组件 |
| HandlerMapping | 根据 URL、HTTP 方法等找到处理器(Controller 方法) |
| HandlerAdapter | 适配不同处理器类型,真正调用 Controller 方法 |
| HandlerInterceptor | 前置/后置/完成拦截(登录校验、日志,可选) |
| ViewResolver | 把逻辑视图名解析为具体视图(JSP 等) |
| HttpMessageConverter | 读写 HTTP 体:JSON ↔ Java 对象(Jackson) |
REST 项目里,ViewResolver 用得少,HttpMessageConverter(Jackson)负责把返回值序列化成 JSON。
4. 请求处理流程
Client 发 HTTP 请求 → Servlet 容器(Tomcat) → Filter 链(编码、安全等,可选) → DispatcherServlet → HandlerMapping:匹配 @GetMapping 等方法 → HandlerInterceptor.preHandle(可选) → HandlerAdapter:调用 Controller 方法 → Controller → Service → Mapper → 返回对象或 ModelAndView → HttpMessageConverter 写 JSON(@ResponseBody / @RestController) → HandlerInterceptor.postHandle / afterCompletion → 响应返回 Client记忆口诀:一进(DispatcherServlet)二找(Mapping)三调(Adapter)四转(Converter/View)。
与 IoC 的关系:上述组件本身也是 Spring 容器里的 Bean;Boot 通过自动配置注册 DispatcherServlet 和默认 HandlerMapping。
5. 常用注解
类级别
| 注解 | 作用 |
|---|---|
@Controller | 标记控制器;方法返回值默认作视图名 |
@RestController | @Controller + @ResponseBody,REST 最常用 |
@RequestMapping | 类/方法路径前缀;可指定 method、consumes、produces |
方法级别映射(Boot 里常用语义化子注解)
| 注解 | HTTP |
|---|---|
@GetMapping | GET |
@PostMapping | POST |
@PutMapping | PUT |
@DeleteMapping | DELETE |
@PatchMapping | PATCH |
参数绑定
| 注解 | 绑定来源 | 示例 |
|---|---|---|
@RequestParam | Query 参数 | ?page=1 → @RequestParam int page |
@PathVariable | 路径变量 | /users/{id} → @PathVariable Long id |
@RequestBody | 请求体 JSON | POST JSON → DTO 对象 |
@RequestHeader | 请求头 | Authorization |
@CookieValue | Cookie | |
@ModelAttribute | 表单 / Model | 传统表单场景 |
校验与响应
| 注解 | 作用 |
|---|---|
@Valid / @Validated | 触发 JSR-303 校验(配合 @NotNull 等) |
@ResponseBody | 返回值直接写入 HTTP 体(@RestController 已含) |
@ResponseStatus | 指定 HTTP 状态码 |
@GetMapping("/{id}")public UserVO get(@PathVariable Long id, @RequestParam(defaultValue = "false") boolean detail) { return userService.find(id, detail);}6. REST API vs 传统 MVC 视图
| REST(前后端分离) | 传统 MVC(服务端渲染) | |
|---|---|---|
| 控制器 | @RestController | @Controller |
| 返回值 | DTO/VO → JSON | 视图名或 ModelAndView |
| 视图 | 无 / 前端 SPA | JSP、Thymeleaf 等 |
| 核心组件 | HttpMessageConverter | ViewResolver |
当前 Java 后端项目以 REST + JSON 为主;面试仍可能问 ModelAndView 和视图解析,知道即可。
7. Spring MVC 与 Spring Boot Web
Spring Boot 的 spring-boot-starter-web 引入 spring-webmvc,并自动配置:
- 内嵌 Tomcat(或换 Jetty/Undertow)
DispatcherServlet与默认HandlerMapping- Jackson
HttpMessageConverter - 静态资源、
application.properties里的server.port等
本质仍是 Spring MVC,只是省掉 XML 和 web.xml 里手动注册 Servlet 的步骤。Web 层进阶(全局异常、Actuator)→ Spring Boot Web、运维与测试。
8. Spring、Spring Boot、Spring Cloud 关系
| 框架 | 定位 |
|---|---|
| Spring Framework | 核心:IoC、AOP、MVC、事务 |
| Spring Boot | 快速构建单个可运行应用(含 Web) |
| Spring Cloud | 微服务治理:注册发现、配置中心、网关、熔断等 |
Boot 可单独做单体或单个微服务;Cloud 建立在 Boot 之上,解决多服务协作。学 MVC 属于 Framework 层,Boot 只是启动与配置方式更简单。
常见陷阱与错误示例
1. Controller 里写事务或复杂业务
@Transactional 标在 Controller 上虽可能生效,但事务边界应放在 Service,便于复用和测试,也避免 Web 层逻辑渗进业务。
2. GET 请求带 @RequestBody
HTTP 规范不禁止,但网关、缓存、部分客户端对 GET body 支持差;查询用 Query/Path,改改用 POST 或 RESTful 设计。
3. 路径变量名与参数名不一致未指定
@PathVariable 默认按参数名匹配;不一致时需 @PathVariable("userId") Long id。
4. 返回 Entity 直接暴露给前端
应返回 VO/DTO,避免把数据库实体、懒加载字段、敏感字段直接序列化到 JSON。
5. 混淆 @Controller 与 @RestController
@Controller 返回 "index" 会被当成视图名;REST 接口误用会导致 404 视图而不是 JSON。API 统一用 @RestController。
6. 忽略 404/405 是 Mapping 问题
404 常是 URL 或 HTTP 方法未匹配到 @XxxMapping;检查类上 @RequestMapping 前缀、是否多写了 /、是否被 context-path 影响。
面试高频问题
更多速查见 Spring 面试题、Spring Cloud 面试题 49 道。
Spring MVC 执行流程?
请求进 DispatcherServlet → HandlerMapping 找处理器 → HandlerAdapter 调 Controller → 返回结果经 ViewResolver 或 HttpMessageConverter 写回客户端。
DispatcherServlet 是什么?
前端控制器(Front Controller),Web 层总入口,解耦 Servlet 容器与 Spring 组件。
@RestController 和 @Controller 区别?
@RestController = @Controller + @ResponseBody,返回值序列化为 JSON 等;@Controller 默认走视图解析。
Spring MVC 和 Spring Boot 关系?
Boot Web 基于 Spring MVC,自动配置 DispatcherServlet、Jackson、内嵌容器;不是两套 Web 框架。
拦截器 Interceptor 和 Filter 区别?
Filter 属于 Servlet 规范,在 DispatcherServlet 之前;Interceptor 属于 Spring MVC,在 DispatcherServlet 之内,能拿到 Handler 信息。
一句话总结
Spring MVC 的核心是 DispatcherServlet 调度 + HandlerMapping/Adapter 定位并调用 Controller;REST 项目靠 HttpMessageConverter 出 JSON,Boot Web 是其自动配置版,业务仍应 Controller 薄、Service 厚。