Spring MVC 的核心是把 HTTP 请求映射到控制器方法,并把参数与返回值转换成合适的形式。以下讨论传统 Servlet MVC,请求流程不直接套用到 WebFlux。
一次请求经过哪些环节?
客户端 → Servlet 容器 → Filter → DispatcherServlet → HandlerMapping 找处理器 → HandlerAdapter 执行 → 参数解析/绑定/校验 → Controller → Service → 返回值处理 → JSON 转换或视图解析 → 响应HandlerMapping 负责找到处理器及相关拦截器链;HandlerAdapter 负责调用不同形式的处理器。REST 接口常直接写响应体,页面控制器则可能返回视图名再由视图解析器处理。
常用注解
| 注解 | 用途 |
|---|---|
| @Controller | 标记控制器,返回字符串时通常按视图名处理 |
| @RestController | 相当于 Controller 加 ResponseBody,通常用于响应体接口 |
| @RequestMapping / @GetMapping 等 | 声明请求路径、方法等匹配条件 |
| @PathVariable | 读取路径变量,如 /users/{id} |
| @RequestParam | 读取请求参数,例如查询串或常见表单参数 |
| @RequestBody | 通过消息转换器解析请求体,常见为 JSON |
| @ResponseBody | 将返回值写入响应体 |
JSON 转换通常由 HttpMessageConverter 与 Jackson 等库完成,不是 @RestController 自己解析 JSON,也不是所有返回值都无条件变成 JSON,具体取决于返回类型、媒体类型和转换器。
参数校验与统一异常
DTO 字段可以声明 @NotNull、@NotBlank 等约束,在适用的入口使用 @Valid 或 @Validated 触发校验。@Validated 还支持分组等使用方式,方法级校验的触发依具体配置与版本而定。
@PostMapping("/orders")public OrderView create(@Valid @RequestBody CreateOrderRequest request) { return orderService.create(request);}@RestControllerAdvice 配合 @ExceptionHandler 可以统一转换控制器处理过程中的异常,例如把参数错误返回为清晰的 400 响应。它不是系统里所有异常的兜底机制:Filter 或后台异步任务中的异常需要对应层处理。
Filter、Interceptor、AOP
| 机制 | 所处位置 | 常见用途 |
|---|---|---|
| Filter | Servlet 容器请求链,通常在 MVC 之前 | 编码、CORS、安全过滤、包装请求响应 |
| Interceptor | Spring MVC 处理器调用链 | 请求日志、处理器相关检查 |
| AOP | Spring Bean 的代理方法调用 | 事务、权限、方法级业务日志 |
它们触发边界不同。MVC 拦截器不必然覆盖所有容器请求,AOP 不会自动拦截绕过代理的方法调用。正式认证授权通常应使用合适的安全框架,不能只靠一个自定义拦截器就认为覆盖了所有入口。
面试回答模板
请求进入 Servlet 容器后经过过滤器和 DispatcherServlet,通过 HandlerMapping 找到处理器,再由 HandlerAdapter 完成参数解析并调用控制器。返回结果交给返回值处理器,写 JSON 或解析视图。参数校验可以在 DTO 与入口声明约束,ControllerAdvice 统一处理 MVC 层异常。Filter、Interceptor、AOP 分别对应容器请求链、MVC 处理器链和 Bean 方法代理层。
自测
- @RequestParam 与 @RequestBody 能混为一谈吗?不能,读取的数据来源和解析机制不同。
- @Controller 返回 “hello” 默认一定写响应文本吗?不是,通常按视图名,需要看 ResponseBody 等配置。
- ControllerAdvice 能兜住所有线程中的异常吗?不能。